Part 55 - What is cross site scripting attack
Suggested Videos
Part 52 - Partial views in mvc
Part 53 - Difference between html.partial and html.renderpartial
Part 54 - T4 templates in asp.net mvc
Cross-site scripting attack also called as XSS attack, is a security vulnerability found in Web applications. XSS allows hackers to inject client-side script into Web pages, and later, if that web page is viewed by others, the stored script gets executed. The consequences of XSS may range from a petty nuisance like displaying an alert() box to a significant security risk, like stealing session cookies.
Let's understand cross site scripting attack with an example. We will be using table tblComments for this demo.
CREATE TABLE tblComments
(
Id INT IDENTITY PRIMARY KEY,
Name NVARCHAR(50),
Comments NVARCHAR(500)
)
Create an asp.net mvc 4.0 application. Right click on "Models" folder, and add ADO.NET entity data model, based on table tblComments. Change the name of the entity from tblComment to Comment.

Build the solution, to make sure "Comment" model is compiled.
Now right click on Controllers folder, and add a "new controller". Set
1. Controller name = HomeController
2. Template = MVC controller with read/write actions and views, using Entity Framework
3. Model class = Comment
4. Data context class = SampleDBContext
5. Views = Razor (CSHTML)
Click "Add". This generates the HomeController and the required views.
In Create.cshtml view, change
@Html.EditorFor(model => model.Comments)
TO
@Html.TextAreaFor(model => model.Comments)
The above change is to display a multi-line textbox for entering comments.

Part 52 - Partial views in mvc
Part 53 - Difference between html.partial and html.renderpartial
Part 54 - T4 templates in asp.net mvc
Cross-site scripting attack also called as XSS attack, is a security vulnerability found in Web applications. XSS allows hackers to inject client-side script into Web pages, and later, if that web page is viewed by others, the stored script gets executed. The consequences of XSS may range from a petty nuisance like displaying an alert() box to a significant security risk, like stealing session cookies.
Let's understand cross site scripting attack with an example. We will be using table tblComments for this demo.
CREATE TABLE tblComments
(
Id INT IDENTITY PRIMARY KEY,
Name NVARCHAR(50),
Comments NVARCHAR(500)
)
Create an asp.net mvc 4.0 application. Right click on "Models" folder, and add ADO.NET entity data model, based on table tblComments. Change the name of the entity from tblComment to Comment.

Build the solution, to make sure "Comment" model is compiled.
Now right click on Controllers folder, and add a "new controller". Set
1. Controller name = HomeController
2. Template = MVC controller with read/write actions and views, using Entity Framework
3. Model class = Comment
4. Data context class = SampleDBContext
5. Views = Razor (CSHTML)
Click "Add". This generates the HomeController and the required views.
In Create.cshtml view, change
@Html.EditorFor(model => model.Comments)
TO
@Html.TextAreaFor(model => model.Comments)
The above change is to display a multi-line textbox for entering comments.

Now let's inject javascript using the "Create" view. Navigate to "localhost/MVCDemo/Home/Create" view. Type the following client-side script, into "Comments" textbox, and click "Create". We get an error - A potentially dangerous Request.Form value was detected from the client (Comments="<script"). This is one of the security measures in place, to prevent script injecttion, to avoid XSS attack.
<script type="text/javascript">
alert('Your site is hacked');
</script>
Depending on the project requirement, there may be legitimate reasons, to submit html. For example, let's say we want to bold and underline a word in the comment that we type. To bold and underline the word "very good" in the following statement, we would type a statement as shown below and submit.
This website is <b><u>very good</u></b>
To allow this HTML to be submitted. We need to disable input validation. When we click the "Create" button on "Create" view, the "Create()" controller action method that is decorated with [HttpPost] attribute in the "HomeController". To disable input validation, decorate Create() action method with "ValidateInput" attribute as shown below.
[HttpPost]
[ValidateInput(false)]
public ActionResult Create(Comment comment)
{
if (ModelState.IsValid)
{
db.Comments.AddObject(comment);
db.SaveChanges();
return RedirectToAction("Index");
}
return View(comment);
}
Build the solution. Navigate to "Create" view. Enter
Name = Tom
Comments = This website is <b><u>very good</u></b>

Now click "Create". Data gets saved as expected, and the user is redirected to Index action. On the "Index" view, instead of rendering the word "very good" with an under-line and in bold, the encoded html is displayed as shown below.
By default asp.net mvc encodes all html. This is another security measure in place, to prevent XSS attack. To disable html encoding, make the fllowing change on Index.cshtml view.
CHANGE
@Html.DisplayFor(modelItem => item.Comments)
To
@Html.Raw(item.Comments)
Navigate to Index view, and notice that, the word "Very Good" is rendered with an underline and in bold.
The following 2 changes that we have done has opened the doors for XSS.
1. By allowing HTML to be submitted on Create.cshtml view
2. By disabling HTML encoding on Index.cshtml
To initiate a cross site scripting attack
1. Navigate to "Create" view
2. Type the following javascript code in "Comments" textbox
<script type="text/javascript">
alert('Your site is hacked');
</script>
3. Click "Create"
Refresh Index view and notice that javascript alert() box is displayed, stating that the site is hacked. By injecting script, it is also very easy to steal session cookies. These stolen session cookies can then be used to log into the site and do destructive things.
So, in short, by allowing HTML to be submitted and disabling HTML encoding we are opening doors for XSS attack.
In our next video, we will discuss preventing XSS while allowing only the HTML that we want to accept.
Suggested Videos
Part 53 - Difference between html.partial and html.renderpartial
Part 54 - T4 templates in asp.net mvc
Part 55 - What is cross site scripting attack
In this video, we will discuss preventing XSS while allowing only the HTML that we want to accept. For example, we only want to accept <b> and <u> tags.
To achieve this let's filter the user input, and accept only <b></b> and <u></u> tags. The following code,
1. Disables input validation
2. Encodes all the input that is coming from the user
3. Finally we selectively replace, the encoded html with the HTML elements that we want to allow.
[HttpPost]
// Input validation is disabled, so the users can submit HTML
[ValidateInput(false)]
public ActionResult Create(Comment comment)
{
StringBuilder sbComments = new StringBuilder();
// Encode the text that is coming from comments textbox
sbComments.Append(HttpUtility.HtmlEncode(comment.Comments));
// Only decode bold and underline tags
sbComments.Replace("<b>", "<b>");
sbComments.Replace("</b>", "</b>");
sbComments.Replace("<u>", "<u>");
sbComments.Replace("</u>", "</u>");
comment.Comments = sbComments.ToString();
// HTML encode the text that is coming from name textbox
string strEncodedName = HttpUtility.HtmlEncode(comment.Name);
comment.Name = strEncodedName;
if (ModelState.IsValid)
{
db.Comments.AddObject(comment);
db.SaveChanges();
return RedirectToAction("Index");
}
return View(comment);
}
Warning: Relying on just filtering the user input, cannot guarantee XSS elimination. XSS can happen in different ways and forms. This is just one example. Please read MSDN documentation on XSS and it's counter measures.
Part 53 - Difference between html.partial and html.renderpartial
Part 54 - T4 templates in asp.net mvc
Part 55 - What is cross site scripting attack
In this video, we will discuss preventing XSS while allowing only the HTML that we want to accept. For example, we only want to accept <b> and <u> tags.
To achieve this let's filter the user input, and accept only <b></b> and <u></u> tags. The following code,
1. Disables input validation
2. Encodes all the input that is coming from the user
3. Finally we selectively replace, the encoded html with the HTML elements that we want to allow.
[HttpPost]
// Input validation is disabled, so the users can submit HTML
[ValidateInput(false)]
public ActionResult Create(Comment comment)
{
StringBuilder sbComments = new StringBuilder();
// Encode the text that is coming from comments textbox
sbComments.Append(HttpUtility.HtmlEncode(comment.Comments));
// Only decode bold and underline tags
sbComments.Replace("<b>", "<b>");
sbComments.Replace("</b>", "</b>");
sbComments.Replace("<u>", "<u>");
sbComments.Replace("</u>", "</u>");
comment.Comments = sbComments.ToString();
// HTML encode the text that is coming from name textbox
string strEncodedName = HttpUtility.HtmlEncode(comment.Name);
comment.Name = strEncodedName;
if (ModelState.IsValid)
{
db.Comments.AddObject(comment);
db.SaveChanges();
return RedirectToAction("Index");
}
return View(comment);
}
Warning: Relying on just filtering the user input, cannot guarantee XSS elimination. XSS can happen in different ways and forms. This is just one example. Please read MSDN documentation on XSS and it's counter measures.
Suggested Videos
Part 54 - T4 templates in asp.net mvc
Part 55 - What is cross site scripting attack
Part 56 - How to prevent cross site scripting attack
In this video, we will discuss razor view syntax.
Use @ symbol to switch between c# code and html.
@for (int i = 1; i <= 10; i++)
{
<b>@i</b>
}
Output:
1 2 3 4 5 6 7 8 9 10
Use @{ } to define a code block. If we want to define some variables and perform calculations, then use code block. The following code block defines 2 variables and computes the sum of first 10 even and odd numbers.
@{
int SumOfEvenNumbers = 0;
int SumOfOddNumbers = 0;
for(int i =1; i<=10; i++)
{
if(i %2 == 0)
{
SumOfEvenNumbers = SumOfEvenNumbers + i;
}
else
{
SumOfOddNumbers = SumOfOddNumbers + i;
}
}
}
<h3>Sum of Even Numbers = @SumOfEvenNumbers</h3>
<h3>Sum of Odd Numbers = @SumOfOddNumbers</h3>
Output:
Sum of Even Numbers = 30
Sum of Odd Numbers = 25
Use <text> element or @: to switch between c# code and literal text
@for (int i = 1; i <= 10; i++)
{
<b>@i</b>
if (i % 2 == 0)
{
<text> - Even </text>
}
else
{
<text> - Odd </text>
}
<br />
}
The above program can be re-written using @: as shown below.
@for (int i = 1; i <= 10; i++)
{
<b>@i</b>
if (i % 2 == 0)
{
@: - Even
}
else
{
@: - Odd
}
<br />
}
Output:
1 - Odd
2 - Even
3 - Odd
4 - Even
5 - Odd
6 - Even
7 - Odd
8 - Even
9 - Odd
10 - Even
Part 54 - T4 templates in asp.net mvc
Part 55 - What is cross site scripting attack
Part 56 - How to prevent cross site scripting attack
In this video, we will discuss razor view syntax.
Use @ symbol to switch between c# code and html.
@for (int i = 1; i <= 10; i++)
{
<b>@i</b>
}
Output:
1 2 3 4 5 6 7 8 9 10
Use @{ } to define a code block. If we want to define some variables and perform calculations, then use code block. The following code block defines 2 variables and computes the sum of first 10 even and odd numbers.
@{
int SumOfEvenNumbers = 0;
int SumOfOddNumbers = 0;
for(int i =1; i<=10; i++)
{
if(i %2 == 0)
{
SumOfEvenNumbers = SumOfEvenNumbers + i;
}
else
{
SumOfOddNumbers = SumOfOddNumbers + i;
}
}
}
<h3>Sum of Even Numbers = @SumOfEvenNumbers</h3>
<h3>Sum of Odd Numbers = @SumOfOddNumbers</h3>
Output:
Sum of Even Numbers = 30
Sum of Odd Numbers = 25
Use <text> element or @: to switch between c# code and literal text
@for (int i = 1; i <= 10; i++)
{
<b>@i</b>
if (i % 2 == 0)
{
<text> - Even </text>
}
else
{
<text> - Odd </text>
}
<br />
}
The above program can be re-written using @: as shown below.
@for (int i = 1; i <= 10; i++)
{
<b>@i</b>
if (i % 2 == 0)
{
@: - Even
}
else
{
@: - Odd
}
<br />
}
Output:
1 - Odd
2 - Even
3 - Odd
4 - Even
5 - Odd
6 - Even
7 - Odd
8 - Even
9 - Odd
10 - Even
Part 58 - Razor views in mvc continued
Suggested Videos
Part 55 - What is cross site scripting attack
Part 56 - How to prevent cross site scripting attack
Part 57 - Razor views in mvc
In this video, we will discuss razor view syntax. This is continuation to Part 57, so please watch Part 57, before proceeding.
Use @* *@ to comment in razor views
@*This is a comment
in razor views*@
Transition between c# expressions and literal text
@{
int day = 31;
int month = 12;
int year = 2013;
}
Date is @day-@month-@year
Output:
Date is 31-12-2013
Using explicit code nugget
@for (int i = 1; i <= 5; i++)
{
<img src="~/Images/@(i).png" />
}
The above code generates the following HTML
<img src="/MVCDemo/Images/1.png" />
<img src="/MVCDemo/Images/2.png" />
<img src="/MVCDemo/Images/3.png" />
<img src="/MVCDemo/Images/4.png" />
<img src="/MVCDemo/Images/5.png" />
Output:

@ symbol is used as code delimiter in razor views. However, razor is smart enough to recognize the format of internet email address and not to treat the @ symbol as a code delimiter.
This is my email address<br />
<b>kudvenkat@gmail.com</b>
Use @ symbol to escape @
I will meet you @@ office
Output:
I will meet you @ office
Part 55 - What is cross site scripting attack
Part 56 - How to prevent cross site scripting attack
Part 57 - Razor views in mvc
In this video, we will discuss razor view syntax. This is continuation to Part 57, so please watch Part 57, before proceeding.
Use @* *@ to comment in razor views
@*This is a comment
in razor views*@
Transition between c# expressions and literal text
@{
int day = 31;
int month = 12;
int year = 2013;
}
Date is @day-@month-@year
Output:
Date is 31-12-2013
Using explicit code nugget
@for (int i = 1; i <= 5; i++)
{
<img src="~/Images/@(i).png" />
}
The above code generates the following HTML
<img src="/MVCDemo/Images/1.png" />
<img src="/MVCDemo/Images/2.png" />
<img src="/MVCDemo/Images/3.png" />
<img src="/MVCDemo/Images/4.png" />
<img src="/MVCDemo/Images/5.png" />
Output:

@ symbol is used as code delimiter in razor views. However, razor is smart enough to recognize the format of internet email address and not to treat the @ symbol as a code delimiter.
This is my email address<br />
<b>kudvenkat@gmail.com</b>
Use @ symbol to escape @
I will meet you @@ office
Output:
I will meet you @ office
Suggested Videos
Part 56 - How to prevent cross site scripting attack
Part 57 - Razor views in mvc
Part 58 - Razor views in mvc continued
What is the advantage of using _Layout.cshtml view?
Layout views provide the advantage of maintaining consistent look and feel across all the views in an mvc application. A typical layout view consists of
1. Header
2. Footer
3. Navigation menu
4. View specific content

Part 56 - How to prevent cross site scripting attack
Part 57 - Razor views in mvc
Part 58 - Razor views in mvc continued
What is the advantage of using _Layout.cshtml view?
Layout views provide the advantage of maintaining consistent look and feel across all the views in an mvc application. A typical layout view consists of
1. Header
2. Footer
3. Navigation menu
4. View specific content

Rather than having all of these sections, in each and every view, we can define them in a layout view and then inherit that look and feel in all the views. With layout views, maintaining the consistent look and feel across all the views becomes much easier, as we have only one layout file to modify, should there be any change. The change will then be immediately reflected across all the views in entire application.
Let us now create a layout view with
1. Header
2. Footer
3. Navigation menu and
4. a place to plugin view specific content
Step 1: Create an empty asp.net mvc4 application.
Step 2: Right click on "Views" folder and add "Shared" folder.
Step 3: Right click on "Shared" folder and add "_Layout.cshtml" view. This is our layout view, where we will define the site wide look and feel. The layout file can have any name, and will have .cshtml file extension. Copy and paste the following html
<html>
<head>
<title>@ViewBag.Title</title>
@*All the javascript and css files that are required by the
application can be referenced here so that there is no
need to reference them in each and every view*@
</head>
<body>
<table border="1" style="width:800px; font-family:Arial">
<tr>
<td colspan="2" style="text-align:center">
<h3>Website Header</h3>
</td>
</tr>
<tr>
<td style="width:200px">
<h3>Menu</h3>
</td>
<td style="width:600px">
@RenderBody()
</td>
</tr>
<tr>
<td colspan="2" style="text-align:center; font-size:x-small">
<h3>Website Footer</h3>
</td>
</tr>
</table>
</body>
</html>
Points to note:
1. View specific title is retrieved using @ViewBag.Title.
2. View specific content will be plugged-in at the location, where RenderBody() function is called.
Step 4: Let us use the following table tblEmployee, and generate a few views that can be used with our layout view.
Create table tblEmployee
(
Id int identity primary key,
FirstName nvarchar(50),
LastName nvarchar(50),
Salary int
)
Insert into tblEmployee values('Tom', 'S', 5000)
Insert into tblEmployee values('Mary', 'P', 8000)
Insert into tblEmployee values('Ben', 'K', 3000)
Step 5: Add ADO.NET entity data model based on the above table. Build the solution, so that Employee model class is compiled.
Step 6: Add a HomeController, with the following settings, so that Index, Details, Create, Edit and Delete views are auto-generated.
1. Controller name - HomeController
2. Template - MVC controller with read/write actions and views, using Entity Framework
3. Model class - Employee
4. Data context class - SampleDBContext
5. Views - Razor
Step 7: Now, we need to make modifications to Index.cshtml view, to use _Layout.cshtml layout view. Copy and paste the following code just below, @model declaration. Notice that, we are storing title in ViewBag object. The layout view is going to retrieve it from viewbag and use it as the title. The next statement, specifies the layout file to use.
@{
ViewBag.Title = "Employee List Page";
Layout = "~/Views/Shared/_Layout.cshtml";
}
At this point navigate to Index view and notice that, it uses the layout file that we have defined.
Step 8: Make the following modifications to layout view. Replace
1. Website Header with Employee Portal
2. <h3>Website Footer</h3> with © 2013 Pragim Technologes
3. <h3>Menu</h3> with @Html.ActionLink("Employee List", "Index")
Save changes and navigate to Index view. Now click on "Edit" link. The page crashes. To fix it, delete "Scripts" section that is at the bottom of the Edit view. Refresh the page. Notice that, we don't have error now, but this view is not using the layout view. To fix it, we need to include the following code, as we did on index view.
@{
ViewBag.Title = "Employee Edit Page";
Layout = "~/Views/Shared/_Layout.cshtml";
}
In our next video, we will discuss - How to specify layout view setting for all the views at one place

Suggested Videos
Part 57 - Razor views in mvc
Part 58 - Razor views in mvc continued
Part 59 - Layout view in mvc
In this video, we will discuss the advantage of using _ViewStart.cshtml. Please watch Part 59, before proceeding.
In Part 59, we discussed that, to associate a view with a layout file, we have to set Layout property on each and every view. This violates DRY (Don't Repeat Yourself) principle, and has the following disadvantages
1. Redundant code.
2. Maintenance overhead. To use a different layout file, all the views need to be updated.
What is _ViewStart.cshtml file?
ASP.NET MVC 3, has introduced _ViewStart.cshtml. Specify the Layout property in this file and place it in the Views folder. All the views will then use the layout file that is specified in _ViewStart.cshtml. This eliminates the need to specify Layout property on each and every view, and making them more cleaner and maintainable.

If you want a set of views in a specific folder, to use a different layout file, then you can include another _ViewStart.cshtml file in that specific folder.
When I use _ViewStart.cshtml file, can I still set Layout property on individual views?
Yes, if you want to use a layout file that is different from what is specified in _ViewStart.cshtml
Where else can I specify a layout file?
Layout file can also be specified in a controller action method or in an action filter.
In Controller Action Method:
Specify which layout to use when returning a view inside a controller action
public ActionResult Create()
{
return View("Create", "_Layout");
}
We will discuss action filters in a later video session.
Can we write some logic in "_ViewStart.cshtml" to dynamically specify which layout file to use?
Yes, the following code will change the layout file to use based on the browser type.
If the browser is google chrome,
then "_Layout.cshtml" layout file is used
Else
"_DifferentLayout.cshtml" layout file is used
Code in "_ViewStart.cshtml" file
@{
Layout = Request.Browser.IsBrowser("Chrome") ? "~/Views/Shared/_Layout.cshtml" : "~/Views/Shared/_DifferentLayout.cshtml" ;
}
All partial views in my application are now using the layout file specified in "_ViewStart.cshtml". How do I prevent these partial views from using a layout file?
Details action method below, returns "_Employee" partial view, and is using the layout file specified in "_ViewStart.cshtml"
public ActionResult Details(int id)
{
Employee employee = db.Employees.Single(e => e.Id == id);
return View("_Employee", employee);
}
To prevent this partial view from using the layout file, specified in "_ViewStart.cshtml", return "PartialViewResult" from the controller action method as shown below.
public PartialViewResult Details(int id)
{
Employee employee = db.Employees.Single(e => e.Id == id);
return PartialView("_Employee", employee);
}
What will be the layout file extension, if VB.NET is my programming language?
.vbhtml
In our next video, we will discuss using named sections in a layout file.
Part 57 - Razor views in mvc
Part 58 - Razor views in mvc continued
Part 59 - Layout view in mvc
In this video, we will discuss the advantage of using _ViewStart.cshtml. Please watch Part 59, before proceeding.
In Part 59, we discussed that, to associate a view with a layout file, we have to set Layout property on each and every view. This violates DRY (Don't Repeat Yourself) principle, and has the following disadvantages
1. Redundant code.
2. Maintenance overhead. To use a different layout file, all the views need to be updated.
What is _ViewStart.cshtml file?
ASP.NET MVC 3, has introduced _ViewStart.cshtml. Specify the Layout property in this file and place it in the Views folder. All the views will then use the layout file that is specified in _ViewStart.cshtml. This eliminates the need to specify Layout property on each and every view, and making them more cleaner and maintainable.

If you want a set of views in a specific folder, to use a different layout file, then you can include another _ViewStart.cshtml file in that specific folder.
When I use _ViewStart.cshtml file, can I still set Layout property on individual views?
Yes, if you want to use a layout file that is different from what is specified in _ViewStart.cshtml
Where else can I specify a layout file?
Layout file can also be specified in a controller action method or in an action filter.
In Controller Action Method:
Specify which layout to use when returning a view inside a controller action
public ActionResult Create()
{
return View("Create", "_Layout");
}
We will discuss action filters in a later video session.
Can we write some logic in "_ViewStart.cshtml" to dynamically specify which layout file to use?
Yes, the following code will change the layout file to use based on the browser type.
If the browser is google chrome,
then "_Layout.cshtml" layout file is used
Else
"_DifferentLayout.cshtml" layout file is used
Code in "_ViewStart.cshtml" file
@{
Layout = Request.Browser.IsBrowser("Chrome") ? "~/Views/Shared/_Layout.cshtml" : "~/Views/Shared/_DifferentLayout.cshtml" ;
}
All partial views in my application are now using the layout file specified in "_ViewStart.cshtml". How do I prevent these partial views from using a layout file?
Details action method below, returns "_Employee" partial view, and is using the layout file specified in "_ViewStart.cshtml"
public ActionResult Details(int id)
{
Employee employee = db.Employees.Single(e => e.Id == id);
return View("_Employee", employee);
}
To prevent this partial view from using the layout file, specified in "_ViewStart.cshtml", return "PartialViewResult" from the controller action method as shown below.
public PartialViewResult Details(int id)
{
Employee employee = db.Employees.Single(e => e.Id == id);
return PartialView("_Employee", employee);
}
What will be the layout file extension, if VB.NET is my programming language?
.vbhtml
In our next video, we will discuss using named sections in a layout file.
Suggested Videos
Part 58 - Razor views in mvc continued
Part 59 - Layout view in mvc
Part 60 - ViewStart in asp.net mvc
Let us understand sections in a layout file with an example. Please watch Parts 59 and 60 from mvc tutorial before proceeding.
At the moment on all the views(Index, Create, Edit, Details & Delete), we see the same navigation menu as shown below.

Let us say we want to change the navigation menu dynamically. For example, if I am on the Edit view, then I want the navigation menu to contain links for List, Details and Delete views as shown below.

Here are the steps to achieve this using sections in layout file
Step 1: Define "Menu" section in Edit view. To define a section, use @section followed by, the name of the section. The menu section, is going to display List, Details and Delete links.
@section Menu
{
@Html.ActionLink("List", "Index") <br />
@Html.ActionLink("Details", "Details", new { id = Model.Id }) <br />
@Html.ActionLink("Delete", "Delete", new { id = Model.Id })
}
Step 2: Specify a location in layout file, where we want the "Menu" section to be rendered.

The above code that is marked in red, is very simple to understand. If you navigate to a view, and if there is a "Menu" section defined in that view, then that content will be injected, else, the default content that is specified in the layout file is used.
For example, Navigate to Edit view. Since "Edit" view has got "Menu" section defined, the content from that section (i.e List, Details and Delete links ) will be displayed.
Now navigate to "Delete" view. "Menu" section is not defined in this view, so default content from the layout file (i.e Index action link) will be displayed.
Part 58 - Razor views in mvc continued
Part 59 - Layout view in mvc
Part 60 - ViewStart in asp.net mvc
Let us understand sections in a layout file with an example. Please watch Parts 59 and 60 from mvc tutorial before proceeding.
At the moment on all the views(Index, Create, Edit, Details & Delete), we see the same navigation menu as shown below.

Let us say we want to change the navigation menu dynamically. For example, if I am on the Edit view, then I want the navigation menu to contain links for List, Details and Delete views as shown below.

Here are the steps to achieve this using sections in layout file
Step 1: Define "Menu" section in Edit view. To define a section, use @section followed by, the name of the section. The menu section, is going to display List, Details and Delete links.
@section Menu
{
@Html.ActionLink("List", "Index") <br />
@Html.ActionLink("Details", "Details", new { id = Model.Id }) <br />
@Html.ActionLink("Delete", "Delete", new { id = Model.Id })
}
Step 2: Specify a location in layout file, where we want the "Menu" section to be rendered.

The above code that is marked in red, is very simple to understand. If you navigate to a view, and if there is a "Menu" section defined in that view, then that content will be injected, else, the default content that is specified in the layout file is used.
For example, Navigate to Edit view. Since "Edit" view has got "Menu" section defined, the content from that section (i.e List, Details and Delete links ) will be displayed.
Now navigate to "Delete" view. "Menu" section is not defined in this view, so default content from the layout file (i.e Index action link) will be displayed.
Part 62 - Implementing search functionality in asp.net mvc
Suggested Videos
Part 59 - Layout view in mvc
Part 60 - ViewStart in asp.net mvc
Part 61 - Named sections in layout files in mvc
In this video, we will discuss, implementing search page in an asp.net mvc application. We should be able to search by Employee Name and Gender. The search page should be as shown below.

We will be using table tblEmployee for this demo. Use the script below to create and populate the table with sample data.
Create table tblEmployee
(
ID int identity primary key,
Name nvarchar(50),
Gender nvarchar(10),
Email nvarchar(50)
)
Insert into tblEmployee values('Sara Nani', 'Female', 'Sara.Nani@test.com')
Insert into tblEmployee values('James Histo', 'Male', 'James.Histo@test.com')
Insert into tblEmployee values('Mary Jane', 'Female', 'Mary.Jane@test.com')
Insert into tblEmployee values('Paul Sensit', 'Male', 'Paul.Sensit@test.com')
Step 1: Create an empty asp.net mvc 4 application.
Step 2: Generate ADO.NET entity data model from database using table tblEmployee. Change the entity name from tblEmployee to Employee. Save changes and build the application.
Step 3: Add HomeController with the following settings.
a) Controller name = HomeController
b) Template = MVC controller with read/write actions and views, using Entity Framework
c) Model class = Employee
d) Data context class = SampleDBContext
e) Views = Razor
Step 4: Modify the Index() action method in HomeController as shown below.
public ActionResult Index(string searchBy, string search)
{
if (searchBy == "Gender")
{
return View(db.Employees.Where(x => x.Gender == search || search == null).ToList());
}
else
{
return View(db.Employees.Where(x => x.Name.StartsWith(search) || search == null).ToList());
}
}
Step 5: Copy and paste the following code in Index.cshtml view.
@model IEnumerable<MVCDemo.Models.Employee>
@{
ViewBag.Title = "Index";
}
<div style="font-family:Arial">
<h2>Employee List</h2>
<p>
@using (@Html.BeginForm("Index", "Home", FormMethod.Get))
{
<b>Search By:</b>
@Html.RadioButton("searchBy", "Name", true) <text>Name</text>
@Html.RadioButton("searchBy", "Gender") <text>Gender</text><br />
@Html.TextBox("search") <input type="submit" value="search" />
}
</p>
<table border="1">
<tr>
<th>
@Html.DisplayNameFor(model => model.Name)
</th>
<th>
@Html.DisplayNameFor(model => model.Gender)
</th>
<th>
@Html.DisplayNameFor(model => model.Email)
</th>
<th>Action</th>
</tr>
@if (Model.Count() == 0)
{
<tr>
<td colspan="4">
No records match search criteria
</td>
</tr>
}
else
{
foreach (var item in Model)
{
<tr>
<td>
@Html.DisplayFor(modelItem => item.Name)
</td>
<td>
@Html.DisplayFor(modelItem => item.Gender)
</td>
<td>
@Html.DisplayFor(modelItem => item.Email)
</td>
<td>
@Html.ActionLink("Edit", "Edit", new { id = item.ID }) |
@Html.ActionLink("Details", "Details", new { id = item.ID }) |
@Html.ActionLink("Delete", "Delete", new { id = item.ID })
</td>
</tr>
}
}
</table>
</div>
Part 59 - Layout view in mvc
Part 60 - ViewStart in asp.net mvc
Part 61 - Named sections in layout files in mvc
In this video, we will discuss, implementing search page in an asp.net mvc application. We should be able to search by Employee Name and Gender. The search page should be as shown below.

We will be using table tblEmployee for this demo. Use the script below to create and populate the table with sample data.
Create table tblEmployee
(
ID int identity primary key,
Name nvarchar(50),
Gender nvarchar(10),
Email nvarchar(50)
)
Insert into tblEmployee values('Sara Nani', 'Female', 'Sara.Nani@test.com')
Insert into tblEmployee values('James Histo', 'Male', 'James.Histo@test.com')
Insert into tblEmployee values('Mary Jane', 'Female', 'Mary.Jane@test.com')
Insert into tblEmployee values('Paul Sensit', 'Male', 'Paul.Sensit@test.com')
Step 1: Create an empty asp.net mvc 4 application.
Step 2: Generate ADO.NET entity data model from database using table tblEmployee. Change the entity name from tblEmployee to Employee. Save changes and build the application.
Step 3: Add HomeController with the following settings.
a) Controller name = HomeController
b) Template = MVC controller with read/write actions and views, using Entity Framework
c) Model class = Employee
d) Data context class = SampleDBContext
e) Views = Razor
Step 4: Modify the Index() action method in HomeController as shown below.
public ActionResult Index(string searchBy, string search)
{
if (searchBy == "Gender")
{
return View(db.Employees.Where(x => x.Gender == search || search == null).ToList());
}
else
{
return View(db.Employees.Where(x => x.Name.StartsWith(search) || search == null).ToList());
}
}
Step 5: Copy and paste the following code in Index.cshtml view.
@model IEnumerable<MVCDemo.Models.Employee>
@{
ViewBag.Title = "Index";
}
<div style="font-family:Arial">
<h2>Employee List</h2>
<p>
@using (@Html.BeginForm("Index", "Home", FormMethod.Get))
{
<b>Search By:</b>
@Html.RadioButton("searchBy", "Name", true) <text>Name</text>
@Html.RadioButton("searchBy", "Gender") <text>Gender</text><br />
@Html.TextBox("search") <input type="submit" value="search" />
}
</p>
<table border="1">
<tr>
<th>
@Html.DisplayNameFor(model => model.Name)
</th>
<th>
@Html.DisplayNameFor(model => model.Gender)
</th>
<th>
@Html.DisplayNameFor(model => model.Email)
</th>
<th>Action</th>
</tr>
@if (Model.Count() == 0)
{
<tr>
<td colspan="4">
No records match search criteria
</td>
</tr>
}
else
{
foreach (var item in Model)
{
<tr>
<td>
@Html.DisplayFor(modelItem => item.Name)
</td>
<td>
@Html.DisplayFor(modelItem => item.Gender)
</td>
<td>
@Html.DisplayFor(modelItem => item.Email)
</td>
<td>
@Html.ActionLink("Edit", "Edit", new { id = item.ID }) |
@Html.ActionLink("Details", "Details", new { id = item.ID }) |
@Html.ActionLink("Delete", "Delete", new { id = item.ID })
</td>
</tr>
}
}
</table>
</div>
Suggested Videos
Part 60 - ViewStart in asp.net mvc
Part 61 - Named sections in layout files in mvc
Part 62 - Implementing search functionality in asp.net mvc
In this video we will discuss, implementing pagination in an asp.net mvc application. Please watch Part 62, before proceeding.
By the end of this video, the index page should support both search functionality and pagination as shown below.

Step 1: Install PagedList.Mvc using NuGet package manager. PagedList.Mvc is dependent on PagedList. Installing PagedList.Mvc will automatically install PagedList package as well.

Step 2: Include the following using statements in HomeController.cs file
using PagedList.Mvc;
using PagedList;
Modify the Index() action method as shown below. Notice that we are passing page parameter to this function. This parameter is used for specifying the page number. This parameter can be null, and that's the reason we have chosen a nullable integer. We convert the list, to a paged list, using ToPagedList(). Also, notice that, we are using null-coalescing operator. If the "page" parameter is null, then 1 is passed as the page number, else, the value contained in the "page" parameter is used as the page number.
public ActionResult Index(string searchBy, string search, int? page)
{
if (searchBy == "Gender")
{
return View(db.Employees.Where(x => x.Gender == search || search == null).ToList().ToPagedList(page ?? 1, 3));
}
else
{
return View(db.Employees.Where(x => x.Name.StartsWith(search) || search == null).ToList().ToPagedList(page ?? 1, 3));
}
}
Step 3: Make the following modifications to Index.cshtml view
a) Include the following 2 using statements on the view.
@using PagedList.Mvc;
@using PagedList;
b) The model for the view should be IPagedList<Employee>.
@model IPagedList<MVCDemo.Models.Employee>
c) Since, we have changed the model of the view, from IEnumerable<MVCDemo.Models.Employee> to IPagedList<MVCDemo.Models.Employee>, change the section that displays table headings as shown below.
<tr>
<th>
@Html.DisplayNameFor(model => model.First().Name)
</th>
<th>
@Html.DisplayNameFor(model => model.First().Gender)
</th>
<th>
@Html.DisplayNameFor(model => model.First().Email)
</th>
<th>Action</th>
</tr>
d) Finally to display page numbers for paging
@Html.PagedListPager(Model, page => Url.Action("Index", new { page, searchBy = Request.QueryString["searchBy"], search = Request.QueryString["search"] }))
e) If you want to display the pager, only if there are more than 1 page
@Html.PagedListPager(Model, page => Url.Action("Index", new { page, searchBy = Request.QueryString["searchBy"], search = Request.QueryString["search"] }), new PagedListRenderOptions() { Display = PagedListDisplayMode.IfNeeded })
f) If you want to display, the current active page and the total number of pages
@Html.PagedListPager(Model, page => Url.Action("Index", new { page, searchBy = Request.QueryString["searchBy"], search = Request.QueryString["search"] }), new PagedListRenderOptions() { Display = PagedListDisplayMode.IfNeeded, DisplayPageCountAndCurrentLocation = true })
g) If you want to display the number of rows displayed, of the total number of rows available.
@Html.PagedListPager(Model, page => Url.Action("Index", new { page, searchBy = Request.QueryString["searchBy"], search = Request.QueryString["search"] }), new PagedListRenderOptions() { Display = PagedListDisplayMode.IfNeeded, DisplayItemSliceAndTotal = true })
Part 60 - ViewStart in asp.net mvc
Part 61 - Named sections in layout files in mvc
Part 62 - Implementing search functionality in asp.net mvc
In this video we will discuss, implementing pagination in an asp.net mvc application. Please watch Part 62, before proceeding.
By the end of this video, the index page should support both search functionality and pagination as shown below.

Step 1: Install PagedList.Mvc using NuGet package manager. PagedList.Mvc is dependent on PagedList. Installing PagedList.Mvc will automatically install PagedList package as well.

Step 2: Include the following using statements in HomeController.cs file
using PagedList.Mvc;
using PagedList;
Modify the Index() action method as shown below. Notice that we are passing page parameter to this function. This parameter is used for specifying the page number. This parameter can be null, and that's the reason we have chosen a nullable integer. We convert the list, to a paged list, using ToPagedList(). Also, notice that, we are using null-coalescing operator. If the "page" parameter is null, then 1 is passed as the page number, else, the value contained in the "page" parameter is used as the page number.
public ActionResult Index(string searchBy, string search, int? page)
{
if (searchBy == "Gender")
{
return View(db.Employees.Where(x => x.Gender == search || search == null).ToList().ToPagedList(page ?? 1, 3));
}
else
{
return View(db.Employees.Where(x => x.Name.StartsWith(search) || search == null).ToList().ToPagedList(page ?? 1, 3));
}
}
Step 3: Make the following modifications to Index.cshtml view
a) Include the following 2 using statements on the view.
@using PagedList.Mvc;
@using PagedList;
b) The model for the view should be IPagedList<Employee>.
@model IPagedList<MVCDemo.Models.Employee>
c) Since, we have changed the model of the view, from IEnumerable<MVCDemo.Models.Employee> to IPagedList<MVCDemo.Models.Employee>, change the section that displays table headings as shown below.
<tr>
<th>
@Html.DisplayNameFor(model => model.First().Name)
</th>
<th>
@Html.DisplayNameFor(model => model.First().Gender)
</th>
<th>
@Html.DisplayNameFor(model => model.First().Email)
</th>
<th>Action</th>
</tr>
d) Finally to display page numbers for paging
@Html.PagedListPager(Model, page => Url.Action("Index", new { page, searchBy = Request.QueryString["searchBy"], search = Request.QueryString["search"] }))
e) If you want to display the pager, only if there are more than 1 page
@Html.PagedListPager(Model, page => Url.Action("Index", new { page, searchBy = Request.QueryString["searchBy"], search = Request.QueryString["search"] }), new PagedListRenderOptions() { Display = PagedListDisplayMode.IfNeeded })
f) If you want to display, the current active page and the total number of pages
@Html.PagedListPager(Model, page => Url.Action("Index", new { page, searchBy = Request.QueryString["searchBy"], search = Request.QueryString["search"] }), new PagedListRenderOptions() { Display = PagedListDisplayMode.IfNeeded, DisplayPageCountAndCurrentLocation = true })
g) If you want to display the number of rows displayed, of the total number of rows available.
@Html.PagedListPager(Model, page => Url.Action("Index", new { page, searchBy = Request.QueryString["searchBy"], search = Request.QueryString["search"] }), new PagedListRenderOptions() { Display = PagedListDisplayMode.IfNeeded, DisplayItemSliceAndTotal = true })
Part 64 - Implement sorting in asp.net mvc
Suggested Videos
Part 61 - Named sections in layout files in mvc
Part 62 - Implementing search functionality in asp.net mvc
Part 63 - Implement paging in asp.net mvc
In this video, we will discuss, implementing sort functionality in an asp.net mvc application. We will be working with the example that we started in Part 62. So, please watch Parts 62 and 63 before proceeding with this video.
We want to support bi-directional sorting by Name and Gender columns. Here's the requirement
1. Name & Gender columns must be click-able hyperlinks
2. Clicking on the column headers should sort the data. If the data is not already sorted by the column on which you have clicked, the data should be sorted in ascending order. Clicking again on the same column should sort the data in descending order.
3. By default, the data should be sorted by "Name" in ascending order.
By the end of this video, the output should be as shown below. Notice that "Name" and "Gender" columns are rendered as hyperlinks, which the user can click to sort data.

Step 1: Modify the "Index()" action method in HomeController as shown below.
public ActionResult Index(string searchBy, string search, int? page, string sortBy)
{
ViewBag.NameSort = String.IsNullOrEmpty(sortBy) ? "Name desc" : "";
ViewBag.GenderSort = sortBy == "Gender" ? "Gender desc" : "Gender";
var employees = db.Employees.AsQueryable();
if (searchBy == "Gender")
{
employees = employees.Where(x => x.Gender == search || search == null);
}
else
{
employees = employees.Where(x => x.Name.StartsWith(search) || search == null);
}
switch (sortBy)
{
case "Name desc":
employees = employees.OrderByDescending(x => x.Name);
break;
case "Gender desc":
employees = employees.OrderByDescending(x => x.Gender);
break;
case "Gender":
employees = employees.OrderBy(x => x.Gender);
break;
default:
employees = employees.OrderBy(x => x.Name);
break;
}
return View(employees.ToPagedList(page ?? 1, 3));
}
Step 2: Modify the code in Index.cshtml view as shown below. Please pay attention to the code highlighted with Grey colour.
@using PagedList;
@using PagedList.Mvc;
@model PagedList.IPagedList<MVCDemo.Models.Employee>
@{
ViewBag.Title = "Index";
}
<link href="~/Content/PagedList.css" rel="stylesheet" type="text/css" />
<div style="font-family:Arial">
<h2>Employee List</h2>
<p>
@using (@Html.BeginForm("Index", "Home", FormMethod.Get))
{
<b>Search By:</b>
@Html.RadioButton("searchBy", "Name", true) <text>Name</text>
@Html.RadioButton("searchBy", "Gender") <text>Gender</text><br />
@Html.TextBox("search") <input type="submit" value="search" />
}
</p>
<table border="1">
<tr>
<th>
@Html.ActionLink("Name", "Index", new { sortBy = ViewBag.NameSort, searchBy = Request["searchBy"], search = Request["search"] })
</th>
<th>
@Html.ActionLink("Gender", "Index", new { sortBy = ViewBag.GenderSort, searchBy = Request["searchBy"], search = Request["search"] })
</th>
<th>
@Html.DisplayNameFor(model => model.First().Email)
</th>
<th>Action</th>
</tr>
@if (Model.Count() == 0)
{
<tr>
<td colspan="4">
No records match search criteria
</td>
</tr>
}
else
{
foreach (var item in Model)
{
<tr>
<td>
@Html.DisplayFor(modelItem => item.Name)
</td>
<td>
@Html.DisplayFor(modelItem => item.Gender)
</td>
<td>
@Html.DisplayFor(modelItem => item.Email)
</td>
<td>
@Html.ActionLink("Edit", "Edit", new { id = item.ID }) |
@Html.ActionLink("Details", "Details", new { id = item.ID }) |
@Html.ActionLink("Delete", "Delete", new { id = item.ID })
</td>
</tr>
}
}
</table>
@Html.PagedListPager(Model, page => Url.Action("Index", new { page, searchBy = Request.QueryString["searchBy"], search = Request.QueryString["search"], sortBy = Request["sortBy"] }), new PagedListRenderOptions() { Display = PagedListDisplayMode.IfNeeded })
</div>
Part 61 - Named sections in layout files in mvc
Part 62 - Implementing search functionality in asp.net mvc
Part 63 - Implement paging in asp.net mvc
In this video, we will discuss, implementing sort functionality in an asp.net mvc application. We will be working with the example that we started in Part 62. So, please watch Parts 62 and 63 before proceeding with this video.
We want to support bi-directional sorting by Name and Gender columns. Here's the requirement
1. Name & Gender columns must be click-able hyperlinks
2. Clicking on the column headers should sort the data. If the data is not already sorted by the column on which you have clicked, the data should be sorted in ascending order. Clicking again on the same column should sort the data in descending order.
3. By default, the data should be sorted by "Name" in ascending order.
By the end of this video, the output should be as shown below. Notice that "Name" and "Gender" columns are rendered as hyperlinks, which the user can click to sort data.

Step 1: Modify the "Index()" action method in HomeController as shown below.
public ActionResult Index(string searchBy, string search, int? page, string sortBy)
{
ViewBag.NameSort = String.IsNullOrEmpty(sortBy) ? "Name desc" : "";
ViewBag.GenderSort = sortBy == "Gender" ? "Gender desc" : "Gender";
var employees = db.Employees.AsQueryable();
if (searchBy == "Gender")
{
employees = employees.Where(x => x.Gender == search || search == null);
}
else
{
employees = employees.Where(x => x.Name.StartsWith(search) || search == null);
}
switch (sortBy)
{
case "Name desc":
employees = employees.OrderByDescending(x => x.Name);
break;
case "Gender desc":
employees = employees.OrderByDescending(x => x.Gender);
break;
case "Gender":
employees = employees.OrderBy(x => x.Gender);
break;
default:
employees = employees.OrderBy(x => x.Name);
break;
}
return View(employees.ToPagedList(page ?? 1, 3));
}
Step 2: Modify the code in Index.cshtml view as shown below. Please pay attention to the code highlighted with Grey colour.
@using PagedList;
@using PagedList.Mvc;
@model PagedList.IPagedList<MVCDemo.Models.Employee>
@{
ViewBag.Title = "Index";
}
<link href="~/Content/PagedList.css" rel="stylesheet" type="text/css" />
<div style="font-family:Arial">
<h2>Employee List</h2>
<p>
@using (@Html.BeginForm("Index", "Home", FormMethod.Get))
{
<b>Search By:</b>
@Html.RadioButton("searchBy", "Name", true) <text>Name</text>
@Html.RadioButton("searchBy", "Gender") <text>Gender</text><br />
@Html.TextBox("search") <input type="submit" value="search" />
}
</p>
<table border="1">
<tr>
<th>
@Html.ActionLink("Name", "Index", new { sortBy = ViewBag.NameSort, searchBy = Request["searchBy"], search = Request["search"] })
</th>
<th>
@Html.ActionLink("Gender", "Index", new { sortBy = ViewBag.GenderSort, searchBy = Request["searchBy"], search = Request["search"] })
</th>
<th>
@Html.DisplayNameFor(model => model.First().Email)
</th>
<th>Action</th>
</tr>
@if (Model.Count() == 0)
{
<tr>
<td colspan="4">
No records match search criteria
</td>
</tr>
}
else
{
foreach (var item in Model)
{
<tr>
<td>
@Html.DisplayFor(modelItem => item.Name)
</td>
<td>
@Html.DisplayFor(modelItem => item.Gender)
</td>
<td>
@Html.DisplayFor(modelItem => item.Email)
</td>
<td>
@Html.ActionLink("Edit", "Edit", new { id = item.ID }) |
@Html.ActionLink("Details", "Details", new { id = item.ID }) |
@Html.ActionLink("Delete", "Delete", new { id = item.ID })
</td>
</tr>
}
}
</table>
@Html.PagedListPager(Model, page => Url.Action("Index", new { page, searchBy = Request.QueryString["searchBy"], search = Request.QueryString["search"], sortBy = Request["sortBy"] }), new PagedListRenderOptions() { Display = PagedListDisplayMode.IfNeeded })
</div>
Part 65 - Deleting multiple rows in mvc
Suggested Videos
Part 62 - Implementing search functionality
Part 63 - Implement paging
Part 64 - Implement sorting
In this video, we will discuss deleting multiple rows in an asp.net mvc application.
We will be using table tblEmployee for this demo. Please refer to Part 62, if you need SQL script to create and populate this table.
We want to provide a checkbox next to every row, to enable users to select multiple rows for deletion as shown below.

Step 1: Create an empty asp.net mvc 4 application.
Step 2: Generate ADO.NET entity data model from database using table tblEmployee. Change the entity name from tblEmployee to Employee. Save changes and build the application.
Step 3: Add HomeController with the following settings.
a) Controller name = HomeController
b) Template = Empty MVC controller
Setp 4: Add "Shared" folder under "Views", if it is not already present. Add "EditorTemplates" folder, under "Shared" folder. Right click on "EditorTemplates" folder and "Employee.cshtml" view with the following settings
View name = Employee
View engine = Razor
Create a strongly-typed view = checked
Model class = Employee (MVCDemo.Models)
Scaffold Template = Empty
and finally click "Add"
Step 5: Copy and paste the following code in Employee.cshtml view
@model MVCDemo.Models.Employee
<tr>
<td>
<input type="checkbox" name="employeeIdsToDelete" id="employeeIdsToDelete" value="@Model.ID" />
</td>
<td>
@Model.Name
</td>
<td>
@Model.Gender
</td>
<td>
@Model.Email
</td>
</tr>
Step 6: Copy and paste the following code in HomeController.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using MVCDemo.Models;
namespace MVCTest.Controllers
{
public class HomeController : Controller
{
private SampleDBContext db = new SampleDBContext();
public ActionResult Index()
{
return View(db.Employees.ToList());
}
[HttpPost]
public ActionResult Delete(IEnumerable<int> employeeIdsToDelete)
{
db.Employees.Where(x => employeeIdsToDelete.Contains(x.ID)).ToList().ForEach(db.Employees.DeleteObject);
db.SaveChanges();
return RedirectToAction("Index");
}
}
}
Setp 7: Right click on the Index() action and add "Index" view with the following settings.
View name = Index
View engine = Razor
Create a strongly-typed view = checked
Model class = Employee (MVCDemo.Models)
Scaffold Template = Empty
and finally click "Add"
Setp 8: Copy and paste the following code in Index.cshtml view
@model IEnumerable<MVCDemo.Models.Employee>
<div style="font-family:Arial">
<h2>Employee List</h2>
@using (Html.BeginForm("Delete", "Home", FormMethod.Post))
{
<table border="1">
<thead>
<tr>
<th>
Select
</th>
<th>
Name
</th>
<th>
Gender
</th>
<th>
Email
</th>
</tr>
</thead>
<tbody>
@Html.EditorForModel()
</tbody>
</table>
<input type="submit" value="Delete selected employees" />
}
</div>
In our next video, we will discuss providing a "SELECT ALL" checkbox to select and de-select all rows.
Part 62 - Implementing search functionality
Part 63 - Implement paging
Part 64 - Implement sorting
In this video, we will discuss deleting multiple rows in an asp.net mvc application.
We will be using table tblEmployee for this demo. Please refer to Part 62, if you need SQL script to create and populate this table.
We want to provide a checkbox next to every row, to enable users to select multiple rows for deletion as shown below.

Step 1: Create an empty asp.net mvc 4 application.
Step 2: Generate ADO.NET entity data model from database using table tblEmployee. Change the entity name from tblEmployee to Employee. Save changes and build the application.
Step 3: Add HomeController with the following settings.
a) Controller name = HomeController
b) Template = Empty MVC controller
Setp 4: Add "Shared" folder under "Views", if it is not already present. Add "EditorTemplates" folder, under "Shared" folder. Right click on "EditorTemplates" folder and "Employee.cshtml" view with the following settings
View name = Employee
View engine = Razor
Create a strongly-typed view = checked
Model class = Employee (MVCDemo.Models)
Scaffold Template = Empty
and finally click "Add"
Step 5: Copy and paste the following code in Employee.cshtml view
@model MVCDemo.Models.Employee
<tr>
<td>
<input type="checkbox" name="employeeIdsToDelete" id="employeeIdsToDelete" value="@Model.ID" />
</td>
<td>
@Model.Name
</td>
<td>
@Model.Gender
</td>
<td>
@Model.Email
</td>
</tr>
Step 6: Copy and paste the following code in HomeController.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using MVCDemo.Models;
namespace MVCTest.Controllers
{
public class HomeController : Controller
{
private SampleDBContext db = new SampleDBContext();
public ActionResult Index()
{
return View(db.Employees.ToList());
}
[HttpPost]
public ActionResult Delete(IEnumerable<int> employeeIdsToDelete)
{
db.Employees.Where(x => employeeIdsToDelete.Contains(x.ID)).ToList().ForEach(db.Employees.DeleteObject);
db.SaveChanges();
return RedirectToAction("Index");
}
}
}
Setp 7: Right click on the Index() action and add "Index" view with the following settings.
View name = Index
View engine = Razor
Create a strongly-typed view = checked
Model class = Employee (MVCDemo.Models)
Scaffold Template = Empty
and finally click "Add"
Setp 8: Copy and paste the following code in Index.cshtml view
@model IEnumerable<MVCDemo.Models.Employee>
<div style="font-family:Arial">
<h2>Employee List</h2>
@using (Html.BeginForm("Delete", "Home", FormMethod.Post))
{
<table border="1">
<thead>
<tr>
<th>
Select
</th>
<th>
Name
</th>
<th>
Gender
</th>
<th>
</th>
</tr>
</thead>
<tbody>
@Html.EditorForModel()
</tbody>
</table>
<input type="submit" value="Delete selected employees" />
}
</div>
In our next video, we will discuss providing a "SELECT ALL" checkbox to select and de-select all rows.
Part 66 - Check uncheck all checkboxes with another single checkbox using
jquery
Suggested Videos
Part 63 - Implement paging
Part 64 - Implement sorting
Part 65 - Deleting multiple rows
In this video, we will discuss, how to check/uncheck all checkboxes with another single checkbox using jquery in an asp.net mvc application. Please watch Part 65, before proceeding.
We want the output as shown below

Here is the requirement
1. When the checkbox in the header is selected, all the checkboxes in the respective rows should be selected. If we deselect any of the checkbox, then the header checkbox should be automatically deselected.
2. When the checkbox in the header is deselected, all the checkboxes in the respective rows should be deselected as well. If we start to select each checkbox in the datarows, and upon selecting checkboxes in all the datarows, the checkbox in the header should be selected.
3. We also need a client side confirmation, on the number of rows to be deleted. The selected rows should be deleted from the database table, only when OK button is clicked. If cancel button is clicked, the form should not be posted to the server, and no rows should be deleted.
Here's the required jQuery script. Please paste this in the "Index.cshtml" view.
<script src="~/Scripts/jquery-1.7.1.min.js" type="text/javascript"></script>
<script type="text/javascript" language="javascript">
$(function () {
$("#checkAll").click(function () {
$("input[name='employeeIdsToDelete']").attr("checked", this.checked);
$("input[name='employeeIdsToDelete']").click(function () {
if ($("input[name='employeeIdsToDelete']").length == $("input[name='employeeIdsToDelete']:checked").length) {
$("#checkAll").attr("checked", "checked");
}
else {
$("#checkAll").removeAttr("checked");
}
});
});
$("#btnSubmit").click(function () {
var count = $("input[name='employeeIdsToDelete']:checked").length;
if (count == 0) {
alert("No rows selected to delete");
return false;
}
else {
return confirm(count + " row(s) will be deleted");
}
});
});
</script>
jQuery file can also be referenced from the following website
jQuery - http://code.jquery.com/jquery-latest.min.js
Google - http://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js
Microsoft - http://ajax.microsoft.com/ajax/jQuery/jquery-1.9.1.min.js
Part 63 - Implement paging
Part 64 - Implement sorting
Part 65 - Deleting multiple rows
In this video, we will discuss, how to check/uncheck all checkboxes with another single checkbox using jquery in an asp.net mvc application. Please watch Part 65, before proceeding.
We want the output as shown below

Here is the requirement
1. When the checkbox in the header is selected, all the checkboxes in the respective rows should be selected. If we deselect any of the checkbox, then the header checkbox should be automatically deselected.
2. When the checkbox in the header is deselected, all the checkboxes in the respective rows should be deselected as well. If we start to select each checkbox in the datarows, and upon selecting checkboxes in all the datarows, the checkbox in the header should be selected.
3. We also need a client side confirmation, on the number of rows to be deleted. The selected rows should be deleted from the database table, only when OK button is clicked. If cancel button is clicked, the form should not be posted to the server, and no rows should be deleted.
Here's the required jQuery script. Please paste this in the "Index.cshtml" view.
<script src="~/Scripts/jquery-1.7.1.min.js" type="text/javascript"></script>
<script type="text/javascript" language="javascript">
$(function () {
$("#checkAll").click(function () {
$("input[name='employeeIdsToDelete']").attr("checked", this.checked);
$("input[name='employeeIdsToDelete']").click(function () {
if ($("input[name='employeeIdsToDelete']").length == $("input[name='employeeIdsToDelete']:checked").length) {
$("#checkAll").attr("checked", "checked");
}
else {
$("#checkAll").removeAttr("checked");
}
});
});
$("#btnSubmit").click(function () {
var count = $("input[name='employeeIdsToDelete']:checked").length;
if (count == 0) {
alert("No rows selected to delete");
return false;
}
else {
return confirm(count + " row(s) will be deleted");
}
});
});
</script>
jQuery file can also be referenced from the following website
jQuery - http://code.jquery.com/jquery-latest.min.js
Google - http://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js
Microsoft - http://ajax.microsoft.com/ajax/jQuery/jquery-1.9.1.min.js
Suggested Videos
Part 64 - Implement sorting
Part 65 - Deleting multiple rows
Part 66 - Check uncheck all checkboxes using jquery
In this video, we will discuss action selectors in asp.net mvc
Actions are public methods in an mvc controller that responds to an URL request. You can control or influence which action method gets invoked using action selectors in mvc. Action selectors are attributes that can be applied to an action method in a controller.
ActionName selector: This action selector is used when you want to invoke an action method with a different name, than what is already given to the action method.
For example, the following URL request would invoke Index() action method in HomeController
/Home/Index
public class HomeController : Controller
{
public string Index()
{
return "Index action method invoked";
}
}
If you want to invoke Index() action method, with the following URL
/Home/List
Then decorate the action method with ActionName attribute as shown below.
public class HomeController : Controller
{
[ActionName("List")]
public string Index()
{
return "Index action method invoked";
}
}
Now, if you navigate to /Home/Index, you will get an error - The resource cannot be found.
At the moment, the Index() action method is returning a string, but if it returns a view, should the view be named - Index or List.?
[ActionName("List")]
public ActionResult Index()
{
return View();
}
List should be the view name. If for some reason, you want to use "Index" as the view name, then modify the controller action method as shown below.
[ActionName("List")]
public ActionResult Index()
{
return View("Index");
}
AcceptVerbs selector: Use this selector, when you want to control, the invocation of an action method based on the request type. In the example below, the "Edit" method that is decorated with GET acceptverb responds to the GET request, where as the other "Edit" method responds to POST request. The default is GET. So, if you don't decorate an action method with any accept verb, then, by default, the method responds to GET request.
public class HomeController : Controller
{
[AcceptVerbs(HttpVerbs.Get)]
public ActionResult Edit(int id)
{
Employee employee = GetEmployeeFromDB(id);
return View(employee);
}
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Save(Employee employee)
{
if (ModelState.IsValid)
{
// Save employee to the database
return RedirectToAction("Index");
}
return View(employee);
}
}
HttpGet and HttpPost attributes can be used as shown below. This is an alternative to using AcceptVerbs attribute.
public class HomeController : Controller
{
[HttpGet]
public ActionResult Edit(int id)
{
Employee employee = GetEmployeeFromDB(id);
return View(employee);
}
[HttpPost]
public ActionResult Save(Employee employee)
{
if (ModelState.IsValid)
{
// Save employee to the database
return RedirectToAction("Index");
}
return View(employee);
}
}
Part 64 - Implement sorting
Part 65 - Deleting multiple rows
Part 66 - Check uncheck all checkboxes using jquery
In this video, we will discuss action selectors in asp.net mvc
Actions are public methods in an mvc controller that responds to an URL request. You can control or influence which action method gets invoked using action selectors in mvc. Action selectors are attributes that can be applied to an action method in a controller.
ActionName selector: This action selector is used when you want to invoke an action method with a different name, than what is already given to the action method.
For example, the following URL request would invoke Index() action method in HomeController
/Home/Index
public class HomeController : Controller
{
public string Index()
{
return "Index action method invoked";
}
}
If you want to invoke Index() action method, with the following URL
/Home/List
Then decorate the action method with ActionName attribute as shown below.
public class HomeController : Controller
{
[ActionName("List")]
public string Index()
{
return "Index action method invoked";
}
}
Now, if you navigate to /Home/Index, you will get an error - The resource cannot be found.
At the moment, the Index() action method is returning a string, but if it returns a view, should the view be named - Index or List.?
[ActionName("List")]
public ActionResult Index()
{
return View();
}
List should be the view name. If for some reason, you want to use "Index" as the view name, then modify the controller action method as shown below.
[ActionName("List")]
public ActionResult Index()
{
return View("Index");
}
AcceptVerbs selector: Use this selector, when you want to control, the invocation of an action method based on the request type. In the example below, the "Edit" method that is decorated with GET acceptverb responds to the GET request, where as the other "Edit" method responds to POST request. The default is GET. So, if you don't decorate an action method with any accept verb, then, by default, the method responds to GET request.
public class HomeController : Controller
{
[AcceptVerbs(HttpVerbs.Get)]
public ActionResult Edit(int id)
{
Employee employee = GetEmployeeFromDB(id);
return View(employee);
}
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Save(Employee employee)
{
if (ModelState.IsValid)
{
// Save employee to the database
return RedirectToAction("Index");
}
return View(employee);
}
}
HttpGet and HttpPost attributes can be used as shown below. This is an alternative to using AcceptVerbs attribute.
public class HomeController : Controller
{
[HttpGet]
public ActionResult Edit(int id)
{
Employee employee = GetEmployeeFromDB(id);
return View(employee);
}
[HttpPost]
public ActionResult Save(Employee employee)
{
if (ModelState.IsValid)
{
// Save employee to the database
return RedirectToAction("Index");
}
return View(employee);
}
}
Suggested Videos
Part 65 - Deleting multiple rows
Part 66 - Check uncheck all checkboxes using jquery
Part 67 - Action selectors
In this video, we will discuss the use of NonAction attribute in asp.net mvc
The following questions could be asked in an interview
What is the use of NonAction attribute in MVC?
OR
How do you restrict access to public methods in a controller?
An action method is a public method in a controller that can be invoked using a URL. So, by default, if you have any public method in a controller then it can be invoked using a URL request. To restrict access to public methods in a controller, NonAction attribute can be used. Let's understand this with an example.
We have 2 public methods in HomeController, Method1() and Method2().
Method1 can be invoked using URL /Home/Method1
Method2 can be invoked using URL /Home/Method2
public class HomeController : Controller
{
public string Method1()
{
return "<h1>Method 1 Invoked</h1>";
}
public string Method2()
{
return "<h1>Method 2 Invoked</h1>";
}
}
Let's say Method2() is for doing some internal work, and we don't want it to be invoked using a URL request. To achieve this, decorate Method2() with NonAction attribute.
[NonAction]
public string Method2()
{
return "<h1>Method 2 Invoked</h1>";
}
Now, if you naviage to URL /Home/Method2, you will get an error - The resource cannot be found.
Another way to restrict access to methods in a controller, is by making them private.
private string Method2()
{
return "<h1>Method 2 Invoked</h1>";
}
In general, it's a bad design to have a public method in a controller that is not an action method. If you have any such method for performing business calculations, it should be somewhere in the model and not in the controller.
However, if for some reason, if you want to have public methods in a controller and you don't want to treat them as actions, then use NonAction attribute.
Part 65 - Deleting multiple rows
Part 66 - Check uncheck all checkboxes using jquery
Part 67 - Action selectors
In this video, we will discuss the use of NonAction attribute in asp.net mvc
The following questions could be asked in an interview
What is the use of NonAction attribute in MVC?
OR
How do you restrict access to public methods in a controller?
An action method is a public method in a controller that can be invoked using a URL. So, by default, if you have any public method in a controller then it can be invoked using a URL request. To restrict access to public methods in a controller, NonAction attribute can be used. Let's understand this with an example.
We have 2 public methods in HomeController, Method1() and Method2().
Method1 can be invoked using URL /Home/Method1
Method2 can be invoked using URL /Home/Method2
public class HomeController : Controller
{
public string Method1()
{
return "<h1>Method 1 Invoked</h1>";
}
public string Method2()
{
return "<h1>Method 2 Invoked</h1>";
}
}
Let's say Method2() is for doing some internal work, and we don't want it to be invoked using a URL request. To achieve this, decorate Method2() with NonAction attribute.
[NonAction]
public string Method2()
{
return "<h1>Method 2 Invoked</h1>";
}
Now, if you naviage to URL /Home/Method2, you will get an error - The resource cannot be found.
Another way to restrict access to methods in a controller, is by making them private.
private string Method2()
{
return "<h1>Method 2 Invoked</h1>";
}
In general, it's a bad design to have a public method in a controller that is not an action method. If you have any such method for performing business calculations, it should be somewhere in the model and not in the controller.
However, if for some reason, if you want to have public methods in a controller and you don't want to treat them as actions, then use NonAction attribute.
Part 69 - Action filters in mvc
Suggested Videos
Part 66 - Check uncheck all checkboxes using jquery
Part 67 - Action selectors
Part 68 - What is the use of NonAction attribute
What are action filters in asp.net mvc?
Action filters are attributes that can be applied either on a controller action method or on a controller. When applied at the controller level, they are applicable for all actions within that controller. Action filters allow us to add, pre and post processing logic to an action method. This means, they allow us to modify the way in which an action is executed.
Name a few action filters in mvc?
Authorize
ChildActionOnly
HandleError
OutputCache
RequireHttps
ValidateInput
ValidateAntiForgeryToken
We will discuss each of these action filters in detail in our upcoming videos.
Can you create a custom action filter in mvc?
Yes, we will discuss this in a later video session.
Part 66 - Check uncheck all checkboxes using jquery
Part 67 - Action selectors
Part 68 - What is the use of NonAction attribute
What are action filters in asp.net mvc?
Action filters are attributes that can be applied either on a controller action method or on a controller. When applied at the controller level, they are applicable for all actions within that controller. Action filters allow us to add, pre and post processing logic to an action method. This means, they allow us to modify the way in which an action is executed.
Name a few action filters in mvc?
Authorize
ChildActionOnly
HandleError
OutputCache
RequireHttps
ValidateInput
ValidateAntiForgeryToken
We will discuss each of these action filters in detail in our upcoming videos.
Can you create a custom action filter in mvc?
Yes, we will discuss this in a later video session.
Suggested Videos
Part 67 - Action selectors
Part 68 - What is the use of NonAction attribute
Part 69 - Action filters
In this video, we will discuss Authorize and AllowAnonymous action filters in mvc.
In ASP.NET MVC, by default, all the controller action methods are accessible to both anonymous and authenticated users. If you want action methods, to be available only for authenticated and authorised users, then use Authorize attribute. Let us understand "Authorize" and "AllowAnonymous" action filters with an example.
1. Create a blank asp.net mvc4 application. Name your application MVCDemo.
2. Right click on the "Controllers" folder and add HomeController. Copy and paste the following code.
public class HomeController : Controller
{
public ActionResult NonSecureMethod()
{
return View();
}
public ActionResult SecureMethod()
{
return View();
}
}
3. Right click on NonSecureMethod() and add a view with name = NonSecureMethod. Similarly add a view with name = SecureMethod.
4. Associate MVCDemo project with IIS.
a) Right click on the project name in "solution explorer" and select "Properties"
b) Click on "Web" tab
c) Select "Use Local IIS Web Server". In the "Project Url" textbox, type - http://localhost/MVCDemo
d) Click "Create Virtual Directory" button
5. Open IIS. Expand "Sites" and then "Default Web Site" and select "MVCDemo". Double click on "Authentication" icon. Enable "Anonymous Authentication" and "Windows Authentication", if they are not already enabled.
6. At this point, you will be able to access, both "SecureMethod" and "NonSecureMethod", by visiting the following URLs.
http://localhost/MVCDemo/Home/SecureMethod
http://localhost/MVCDemo/Home/NonSecureMethod
7. If you want "SecureMethod" to be available only for authenticated users, then decorate it with "Authorize" attribute.
[Authorize]
public ActionResult SecureMethod()
{
return View();
}
8. Now, if you navigate to "http://localhost/MVCDemo/Home/SecureMethod", then you will be prompted for your windows credentials. If you don't provide valid windows credentials or if you click cancel, you will get an error - 401 - Unauthorized: Access is denied due to invalid credentials. You do not have permission to view this directory or page using the credentials that you supplied. You should be able to access "NonSecureMethod"
9. Now remove the [Authorize] attribute from SecureMethod(), and apply it on the HomeController.
[Authorize]
public class HomeController : Controller
{
public ActionResult NonSecureMethod()
{
return View();
}
public ActionResult SecureMethod()
{
return View();
}
}
At this point, "Authorize" attribute is applicable for all action methods in the HomeController. So, only authenticated users will be able to access SecureMethod() and NonSecureMethod().
10. To allow anonymous access to NonSecureMethod(), apply [AllowAnonymous] attribute. AllowAnonymous attribute is used to skip authorization enforced by Authorize attribute.
[AllowAnonymous]
public ActionResult NonSecureMethod()
{
return View();
}
Part 67 - Action selectors
Part 68 - What is the use of NonAction attribute
Part 69 - Action filters
In this video, we will discuss Authorize and AllowAnonymous action filters in mvc.
In ASP.NET MVC, by default, all the controller action methods are accessible to both anonymous and authenticated users. If you want action methods, to be available only for authenticated and authorised users, then use Authorize attribute. Let us understand "Authorize" and "AllowAnonymous" action filters with an example.
1. Create a blank asp.net mvc4 application. Name your application MVCDemo.
2. Right click on the "Controllers" folder and add HomeController. Copy and paste the following code.
public class HomeController : Controller
{
public ActionResult NonSecureMethod()
{
return View();
}
public ActionResult SecureMethod()
{
return View();
}
}
3. Right click on NonSecureMethod() and add a view with name = NonSecureMethod. Similarly add a view with name = SecureMethod.
4. Associate MVCDemo project with IIS.
a) Right click on the project name in "solution explorer" and select "Properties"
b) Click on "Web" tab
c) Select "Use Local IIS Web Server". In the "Project Url" textbox, type - http://localhost/MVCDemo
d) Click "Create Virtual Directory" button
5. Open IIS. Expand "Sites" and then "Default Web Site" and select "MVCDemo". Double click on "Authentication" icon. Enable "Anonymous Authentication" and "Windows Authentication", if they are not already enabled.
6. At this point, you will be able to access, both "SecureMethod" and "NonSecureMethod", by visiting the following URLs.
http://localhost/MVCDemo/Home/SecureMethod
http://localhost/MVCDemo/Home/NonSecureMethod
7. If you want "SecureMethod" to be available only for authenticated users, then decorate it with "Authorize" attribute.
[Authorize]
public ActionResult SecureMethod()
{
return View();
}
8. Now, if you navigate to "http://localhost/MVCDemo/Home/SecureMethod", then you will be prompted for your windows credentials. If you don't provide valid windows credentials or if you click cancel, you will get an error - 401 - Unauthorized: Access is denied due to invalid credentials. You do not have permission to view this directory or page using the credentials that you supplied. You should be able to access "NonSecureMethod"
9. Now remove the [Authorize] attribute from SecureMethod(), and apply it on the HomeController.
[Authorize]
public class HomeController : Controller
{
public ActionResult NonSecureMethod()
{
return View();
}
public ActionResult SecureMethod()
{
return View();
}
}
At this point, "Authorize" attribute is applicable for all action methods in the HomeController. So, only authenticated users will be able to access SecureMethod() and NonSecureMethod().
10. To allow anonymous access to NonSecureMethod(), apply [AllowAnonymous] attribute. AllowAnonymous attribute is used to skip authorization enforced by Authorize attribute.
[AllowAnonymous]
public ActionResult NonSecureMethod()
{
return View();
}



Part 71 - childactiononly attribute in mvc
Suggested Videos
Part 68 - What is the use of NonAction attribute
Part 69 - Action filters
Part 70 - Authorize and AllowAnonymous action filters
In this video, we will discuss childactiononly attribute in asp.net mvc. Let us understand this with an example.
Step 1: Create a blank asp.net mvc 4 application
Step 2: Add HomeController. Copy and paste the following code.
public class HomeController : Controller
{
// Public action method that can be invoked using a URL request
public ActionResult Index()
{
return View();
}
// This method is accessible only by a child request. A runtime
// exception will be thrown if a URL request is made to this method
[ChildActionOnly]
public ActionResult Countries(List<String> countryData)
{
return View(countryData);
}
}
Step 3: Right click on the "Countries()" action method and add "Countries" view. This view will render the given list of strings as an un-ordered list.
@model List<string>
@foreach (string country in Model)
{
<ul>
<li>
<b>
@country
</b>
</li>
</ul>
}
Step 4: Right click on the "Index()" action method and add "Index" view. Copy and paste the following code. Notice that, to invoke childaction, we are using Action() HTML Helper.
<h2>Countries List</h2>
@Html.Action("Countries", new { countryData = new List<string>() { "US", "UK", "India" } })
Please Note: Child actions can also be invoked using "RenderAction()" HTMl helper as shown below.
@{
Html.RenderAction("Countries", new { countryData = new List<string>() { "US", "UK", "India" } });
}
Points to remember about "ChildActionOnly" attribute
1. Any action method that is decorated with [ChildActionOnly] attribute is a child action method.
2. Child action methods will not respond to URL requests. If an attempt is made, a runtime error will be thrown stating - Child action is accessible only by a child request.
3. Child action methods can be invoked by making child request from a view using "Action()" and "RenderAction()" html helpers.
4. An action method doesn’t need to have [ChildActionOnly] attribute to be used as a child action, but use this attribute to prevent if you want to prevent the action method from being invoked as a result of a user request.
5. Child actions are typically associated with partial views, although this is not compulsory.
6. Child action methods are different from NonAction methods, in that NonAction methods cannot be invoked using Action() or RenderAction() helpers. We discussed NonAction methods in Part 70 of ASP.NET MVC tutorial series.
7. Using child action methods, it is possible to cache portions of a view. This is the main advantage of child action methods. We will cover this when we discuss [OutputCache] attribute.
Part 68 - What is the use of NonAction attribute
Part 69 - Action filters
Part 70 - Authorize and AllowAnonymous action filters
In this video, we will discuss childactiononly attribute in asp.net mvc. Let us understand this with an example.
Step 1: Create a blank asp.net mvc 4 application
Step 2: Add HomeController. Copy and paste the following code.
public class HomeController : Controller
{
// Public action method that can be invoked using a URL request
public ActionResult Index()
{
return View();
}
// This method is accessible only by a child request. A runtime
// exception will be thrown if a URL request is made to this method
[ChildActionOnly]
public ActionResult Countries(List<String> countryData)
{
return View(countryData);
}
}
Step 3: Right click on the "Countries()" action method and add "Countries" view. This view will render the given list of strings as an un-ordered list.
@model List<string>
@foreach (string country in Model)
{
<ul>
<li>
<b>
@country
</b>
</li>
</ul>
}
Step 4: Right click on the "Index()" action method and add "Index" view. Copy and paste the following code. Notice that, to invoke childaction, we are using Action() HTML Helper.
<h2>Countries List</h2>
@Html.Action("Countries", new { countryData = new List<string>() { "US", "UK", "India" } })
Please Note: Child actions can also be invoked using "RenderAction()" HTMl helper as shown below.
@{
Html.RenderAction("Countries", new { countryData = new List<string>() { "US", "UK", "India" } });
}
Points to remember about "ChildActionOnly" attribute
1. Any action method that is decorated with [ChildActionOnly] attribute is a child action method.
2. Child action methods will not respond to URL requests. If an attempt is made, a runtime error will be thrown stating - Child action is accessible only by a child request.
3. Child action methods can be invoked by making child request from a view using "Action()" and "RenderAction()" html helpers.
4. An action method doesn’t need to have [ChildActionOnly] attribute to be used as a child action, but use this attribute to prevent if you want to prevent the action method from being invoked as a result of a user request.
5. Child actions are typically associated with partial views, although this is not compulsory.
6. Child action methods are different from NonAction methods, in that NonAction methods cannot be invoked using Action() or RenderAction() helpers. We discussed NonAction methods in Part 70 of ASP.NET MVC tutorial series.
7. Using child action methods, it is possible to cache portions of a view. This is the main advantage of child action methods. We will cover this when we discuss [OutputCache] attribute.
Part 72 - HandleError attribute in mvc
Suggested Videos
Part 69 - Action filters
Part 70 - Authorize and AllowAnonymous action filters
Part 71 - ChildActionOnly attribute
In this video, we will discuss HandleError attribute in asp.net mvc. HandleErrorAttribute is used to display friendly error pages to end user when there is an unhandled exception. Let us understand this with an example.
Step 1: Create a blank asp.net mvc 4 application.
Step 2: Add a HomeController. Copy and paste the following code.
public ActionResult Index()
{
throw new Exception("Something went wrong");
}
Notice that, the Index() action method throws an exception. As this exception is not handled, when you run the application, you will get the default "yellow screen of death" which does not make sense to the end user.

Now, let us understand replacing this yellow screen of death, with a friendly error page.
Step 3: Enable custom errors in web.config file, that is present in the root directory of your mvc application. "customErrors" element must be nested under "<system.web>". For detailed explanation on MODE attribute, please watch Part 71 of ASP.NET Tutorial.
<customErrors mode="On">
</customErrors>
Step 4: Add "Shared" folder under "Views" folder. Add Error.cshtml view inside this folder. Paste the following HTML in Error.cdhtml view.
<h2>An unknown problem has occured, please contact Admin</h2>
Run the application, and notice that, you are redirected to the friendly "Error" view, instead of the generic "Yellow screen of death".
We did not apply HandleError attribute anywhere. So how did all this work?
HandleErrorAttribute is added to the GlobalFilters collection in global.asax. When a filter is added to the GlobalFilters collection, then it is applicable for all controllers and their action methods in the entire application.
Right click on "RegisterGlobalFilters()" method in Global.asax, and select "Go To Definition" and you can find the code that adds "HandleErrorAttribute" to GlobalFilterCollection.
public static void RegisterGlobalFilters(GlobalFilterCollection filters)
{
filters.Add(new HandleErrorAttribute());
}
Is the friendly error page displayed for HTTP status code 404?
No, but there is a way to display the friendly error page.
In the HomeController, we do not have List() action method. So, if a user navigates to /Home/List, we get an error - The resource cannot be found. HTTP 404.
To display a friendly error page in this case
Step 1: Add "ErrorController" to controllers folder. Copy and paste the following code.
public class ErrorController : Controller
{
public ActionResult NotFound()
{
return View();
}
}
Step 2: Right click on "Shared" folder and add "NotFound.cshtml" view. Copy and paste the following code.
<h2>Please check the URL. The page you are looking for cannot be found</h2>
Step 3: Change "customErrors" element in web.config as shown below.
<customErrors mode="On">
<error statusCode="404" redirect="~/Error/NotFound"/>
</customErrors>
Part 69 - Action filters
Part 70 - Authorize and AllowAnonymous action filters
Part 71 - ChildActionOnly attribute
In this video, we will discuss HandleError attribute in asp.net mvc. HandleErrorAttribute is used to display friendly error pages to end user when there is an unhandled exception. Let us understand this with an example.
Step 1: Create a blank asp.net mvc 4 application.
Step 2: Add a HomeController. Copy and paste the following code.
public ActionResult Index()
{
throw new Exception("Something went wrong");
}
Notice that, the Index() action method throws an exception. As this exception is not handled, when you run the application, you will get the default "yellow screen of death" which does not make sense to the end user.

Now, let us understand replacing this yellow screen of death, with a friendly error page.
Step 3: Enable custom errors in web.config file, that is present in the root directory of your mvc application. "customErrors" element must be nested under "<system.web>". For detailed explanation on MODE attribute, please watch Part 71 of ASP.NET Tutorial.
<customErrors mode="On">
</customErrors>
Step 4: Add "Shared" folder under "Views" folder. Add Error.cshtml view inside this folder. Paste the following HTML in Error.cdhtml view.
<h2>An unknown problem has occured, please contact Admin</h2>
Run the application, and notice that, you are redirected to the friendly "Error" view, instead of the generic "Yellow screen of death".
We did not apply HandleError attribute anywhere. So how did all this work?
HandleErrorAttribute is added to the GlobalFilters collection in global.asax. When a filter is added to the GlobalFilters collection, then it is applicable for all controllers and their action methods in the entire application.
Right click on "RegisterGlobalFilters()" method in Global.asax, and select "Go To Definition" and you can find the code that adds "HandleErrorAttribute" to GlobalFilterCollection.
public static void RegisterGlobalFilters(GlobalFilterCollection filters)
{
filters.Add(new HandleErrorAttribute());
}
Is the friendly error page displayed for HTTP status code 404?
No, but there is a way to display the friendly error page.
In the HomeController, we do not have List() action method. So, if a user navigates to /Home/List, we get an error - The resource cannot be found. HTTP 404.
To display a friendly error page in this case
Step 1: Add "ErrorController" to controllers folder. Copy and paste the following code.
public class ErrorController : Controller
{
public ActionResult NotFound()
{
return View();
}
}
Step 2: Right click on "Shared" folder and add "NotFound.cshtml" view. Copy and paste the following code.
<h2>Please check the URL. The page you are looking for cannot be found</h2>
Step 3: Change "customErrors" element in web.config as shown below.
<customErrors mode="On">
<error statusCode="404" redirect="~/Error/NotFound"/>
</customErrors>
Part 73 - OutputCache attribute in mvc
Suggested Videos
Part 70 - Authorize and AllowAnonymous action filters
Part 71 - ChildActionOnly attribute
Part 72 - HandleError attribute
In this video, we will discuss OutputCache attribute and partial caching in asp.net mvc. OutputCacheAttribute is used to cache the content returned by a controller action method, so that, the same content does not need to be generated each and every time the same controller action is invoked. Let us understand this with an example.
We will be using table tblEmployee for this demo. Please refer to Part 62 of MVC Tutorial, if you need SQL script to create and populate this table.
Step 1: Add ado.net entity data model based on table tblEmployee. We have discussed doing this several times, in previous sessions of this video series.
Step 2: Add HomeController with the following settings.
a) Controller name = HomeController
b) Template = MVC controller with read/write actions and views, using Entity Framework
c) Model class = Employee
d) Data context class = SampleDBContext
e) Views = Razor
Step 3: Modify the Index() action method in HomeController as shown below. Notice that, we are using OutPutCache attribute to cache the content returned by Index() action method for 10 seconds.
[OutputCache(Duration = 10)]
public ActionResult Index()
{
System.Threading.Thread.Sleep(3000);
return View(db.Employees.ToList());
}
Step 4: Modify code in "Index.cshtml" view as shown below. The modified code is highlighted in Yellow.
@model IEnumerable<MVCDemo.Models.Employee>
<div style="font-family:Arial">
<p>
@Html.ActionLink("Create New", "Create")
</p>
<table border="1">
<tr>
<td colspan="4">
<b>Employee List retrieved @@ @DateTime.Now.ToString()</b>
</td>
</tr>
<tr>
<th>
@Html.DisplayNameFor(model => model.Name)
</th>
<th>
@Html.DisplayNameFor(model => model.Gender)
</th>
<th>
@Html.DisplayNameFor(model => model.Email)
</th>
<th></th>
</tr>
@foreach (var item in Model) {
<tr>
<td>
@Html.DisplayFor(modelItem => item.Name)
</td>
<td>
@Html.DisplayFor(modelItem => item.Gender)
</td>
<td>
@Html.DisplayFor(modelItem => item.Email)
</td>
<td>
@Html.ActionLink("Edit", "Edit", new { id=item.ID }) |
@Html.ActionLink("Details", "Details", new { id=item.ID }) |
@Html.ActionLink("Delete", "Delete", new { id=item.ID })
</td>
</tr>
}
</table>
</div>
When you navigate to /Home/Index, the view ouput is cached for 10 seconds. If you refresh the view, within 10 seconds you will get a cached response. After 10 seconds, the cache expires, code is executed again and the output is cached for another 10 seconds.
Caching specific portion of a view using ChildActionOnly attribute:
Step 1: Remove OutputCache attribute and the line which calls Thread.Sleep(), from the Index() action method in HomeController. After the changes, the Index() action method should be as shown below.
public ActionResult Index()
{
return View(db.Employees.ToList());
}
Step 2: Add GetEmployeeCount() action method to HomeController. Notice that, this method is decorated with OutputCache and ChildActionOnly attributes.
// Child actions can be used to implement partial caching,
// although not necessary. In this case, even if the ChildActionOnly
// attribue is removed, a portion of the view will be cached as expected
[ChildActionOnly]
[OutputCache(Duration = 10)]
public string GetEmployeeCount()
{
return "Employee Count = " + db.Employees.Count().ToString() + "@ " + DateTime.Now.ToString();
}
Step 3: Copy and paste the following code, just below the closing table tag in Index.cshtml view.
<br /><br />
<b> @Html.Action("GetEmployeeCount") </b>
Navigate to /Home/Index. Notice that, everytime you refresh the page, the time in the section of the page that displays employee list changes, but not the time, that displays the employee count. This proves that, only a portion of the view, is cached.
Part 70 - Authorize and AllowAnonymous action filters
Part 71 - ChildActionOnly attribute
Part 72 - HandleError attribute
In this video, we will discuss OutputCache attribute and partial caching in asp.net mvc. OutputCacheAttribute is used to cache the content returned by a controller action method, so that, the same content does not need to be generated each and every time the same controller action is invoked. Let us understand this with an example.
We will be using table tblEmployee for this demo. Please refer to Part 62 of MVC Tutorial, if you need SQL script to create and populate this table.
Step 1: Add ado.net entity data model based on table tblEmployee. We have discussed doing this several times, in previous sessions of this video series.
Step 2: Add HomeController with the following settings.
a) Controller name = HomeController
b) Template = MVC controller with read/write actions and views, using Entity Framework
c) Model class = Employee
d) Data context class = SampleDBContext
e) Views = Razor
Step 3: Modify the Index() action method in HomeController as shown below. Notice that, we are using OutPutCache attribute to cache the content returned by Index() action method for 10 seconds.
[OutputCache(Duration = 10)]
public ActionResult Index()
{
System.Threading.Thread.Sleep(3000);
return View(db.Employees.ToList());
}
Step 4: Modify code in "Index.cshtml" view as shown below. The modified code is highlighted in Yellow.
@model IEnumerable<MVCDemo.Models.Employee>
<div style="font-family:Arial">
<p>
@Html.ActionLink("Create New", "Create")
</p>
<table border="1">
<tr>
<td colspan="4">
<b>Employee List retrieved @@ @DateTime.Now.ToString()</b>
</td>
</tr>
<tr>
<th>
@Html.DisplayNameFor(model => model.Name)
</th>
<th>
@Html.DisplayNameFor(model => model.Gender)
</th>
<th>
@Html.DisplayNameFor(model => model.Email)
</th>
<th></th>
</tr>
@foreach (var item in Model) {
<tr>
<td>
@Html.DisplayFor(modelItem => item.Name)
</td>
<td>
@Html.DisplayFor(modelItem => item.Gender)
</td>
<td>
@Html.DisplayFor(modelItem => item.Email)
</td>
<td>
@Html.ActionLink("Edit", "Edit", new { id=item.ID }) |
@Html.ActionLink("Details", "Details", new { id=item.ID }) |
@Html.ActionLink("Delete", "Delete", new { id=item.ID })
</td>
</tr>
}
</table>
</div>
When you navigate to /Home/Index, the view ouput is cached for 10 seconds. If you refresh the view, within 10 seconds you will get a cached response. After 10 seconds, the cache expires, code is executed again and the output is cached for another 10 seconds.
Caching specific portion of a view using ChildActionOnly attribute:
Step 1: Remove OutputCache attribute and the line which calls Thread.Sleep(), from the Index() action method in HomeController. After the changes, the Index() action method should be as shown below.
public ActionResult Index()
{
return View(db.Employees.ToList());
}
Step 2: Add GetEmployeeCount() action method to HomeController. Notice that, this method is decorated with OutputCache and ChildActionOnly attributes.
// Child actions can be used to implement partial caching,
// although not necessary. In this case, even if the ChildActionOnly
// attribue is removed, a portion of the view will be cached as expected
[ChildActionOnly]
[OutputCache(Duration = 10)]
public string GetEmployeeCount()
{
return "Employee Count = " + db.Employees.Count().ToString() + "@ " + DateTime.Now.ToString();
}
Step 3: Copy and paste the following code, just below the closing table tag in Index.cshtml view.
<br /><br />
<b> @Html.Action("GetEmployeeCount") </b>
Navigate to /Home/Index. Notice that, everytime you refresh the page, the time in the section of the page that displays employee list changes, but not the time, that displays the employee count. This proves that, only a portion of the view, is cached.

Suggested Videos
Part 71 - ChildActionOnly attribute
Part 72 - HandleError attribute
Part 73 - OutputCache attribute
In this video, we will discuss creating CacheProfiles. We will be using the example that we started in Part 73. Please watch Part 73 before proceeding.
To cache the data returned by Index() action method, for 60 seconds, we would use [OutputCache] attribute as shown below.
[OutputCache(Duration=60)]
public ActionResult Index()
{
return View(db.Employees.ToList());
}
In the example above, the OutputCache settings are specified in code. The disadvantage of this approcah is that
1. If you have to apply the same cache settings, to several methods, then the code needs to be duplicated.
2. Later, if we have to change these cache settings, then we need to change them at several places. Maintaining the code becomes complicated. Also, changing the application code requires build and re-deployment.
To overcome these disadvantages, cache settings can be specified in web.config file using cache profiles.
Step 1: Specify cache settings in web.config using cache profiles
<system.web>
<caching>
<outputCacheSettings>
<outputCacheProfiles>
<clear/>
<add name="1MinuteCache" duration="60" varyByParam="none"/>
</outputCacheProfiles>
</outputCacheSettings>
</caching>
</system.web>
Step 2: Reference the cache profile in application code
[OutputCache(CacheProfile = "1MinuteCache")]
public ActionResult Index()
{
return View(db.Employees.ToList());
}
The cache settings are now read from one central location i.e from the web.config file. The advantage of using cache profiles is that
1. You have one place to change the cache settings. Mantainability is much easier.
2. Since the changes are done in web.config, we need not build and redeploy the application.
Using Cache profiles with child action methods
[ChildActionOnly]
[OutputCache(CacheProfile = "1MinuteCache")]
public string GetEmployeeCount()
{
return "Employee Count = " + db.Employees.Count().ToString()
+ "@ " + DateTime.Now.ToString();
}
When Cache profiles are used with child action methods, you will get an error - Duration must be a positive number.
There colud be several ways to make cache profiles work with child action methods. The following is the approach, that I am aware of. Please feel free to leave a comment, if you know of a better way of doing this.
Create a custom OutputCache attribute, that loads the cache settings from the cache profile in web.config.
Step 1: Right click on the project name in solution explorer, and add a folder with name = Common
Setp 2: Right click on "Common" folder and add a class file, with name = PartialCacheAttribute.cs
Step 3: Copy and paste the following code. Notice that, I have named the custom OutputCache attribute as PartialCacheAttribute.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using System.Web.Configuration;
namespace MVCDemo.Common
{
public class PartialCacheAttribute : OutputCacheAttribute
{
public PartialCacheAttribute(string cacheProfileName)
{
OutputCacheSettingsSection cacheSettings = (OutputCacheSettingsSection)WebConfigurationManager.GetSection("system.web/caching/outputCacheSettings");
OutputCacheProfile cacheProfile = cacheSettings.OutputCacheProfiles[cacheProfileName];
Duration = cacheProfile.Duration;
VaryByParam = cacheProfile.VaryByParam;
VaryByCustom = cacheProfile.VaryByCustom;
}
}
}
Step 4: Use PartialCacheAttribute on the child action method, and pass it the name of the cache profile in web.config. Please note that, PartialCacheAttribute is in MVCDemo.Common namespace.
[ChildActionOnly]
[PartialCache("1MinuteCache")]
public string GetEmployeeCount()
{
return "Employee Count = " + db.Employees.Count().ToString()
+ "@ " + DateTime.Now.ToString();
}
Part 71 - ChildActionOnly attribute
Part 72 - HandleError attribute
Part 73 - OutputCache attribute
In this video, we will discuss creating CacheProfiles. We will be using the example that we started in Part 73. Please watch Part 73 before proceeding.
To cache the data returned by Index() action method, for 60 seconds, we would use [OutputCache] attribute as shown below.
[OutputCache(Duration=60)]
public ActionResult Index()
{
return View(db.Employees.ToList());
}
In the example above, the OutputCache settings are specified in code. The disadvantage of this approcah is that
1. If you have to apply the same cache settings, to several methods, then the code needs to be duplicated.
2. Later, if we have to change these cache settings, then we need to change them at several places. Maintaining the code becomes complicated. Also, changing the application code requires build and re-deployment.
To overcome these disadvantages, cache settings can be specified in web.config file using cache profiles.
Step 1: Specify cache settings in web.config using cache profiles
<system.web>
<caching>
<outputCacheSettings>
<outputCacheProfiles>
<clear/>
<add name="1MinuteCache" duration="60" varyByParam="none"/>
</outputCacheProfiles>
</outputCacheSettings>
</caching>
</system.web>
Step 2: Reference the cache profile in application code
[OutputCache(CacheProfile = "1MinuteCache")]
public ActionResult Index()
{
return View(db.Employees.ToList());
}
The cache settings are now read from one central location i.e from the web.config file. The advantage of using cache profiles is that
1. You have one place to change the cache settings. Mantainability is much easier.
2. Since the changes are done in web.config, we need not build and redeploy the application.
Using Cache profiles with child action methods
[ChildActionOnly]
[OutputCache(CacheProfile = "1MinuteCache")]
public string GetEmployeeCount()
{
return "Employee Count = " + db.Employees.Count().ToString()
+ "@ " + DateTime.Now.ToString();
}
When Cache profiles are used with child action methods, you will get an error - Duration must be a positive number.
There colud be several ways to make cache profiles work with child action methods. The following is the approach, that I am aware of. Please feel free to leave a comment, if you know of a better way of doing this.
Create a custom OutputCache attribute, that loads the cache settings from the cache profile in web.config.
Step 1: Right click on the project name in solution explorer, and add a folder with name = Common
Setp 2: Right click on "Common" folder and add a class file, with name = PartialCacheAttribute.cs
Step 3: Copy and paste the following code. Notice that, I have named the custom OutputCache attribute as PartialCacheAttribute.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using System.Web.Configuration;
namespace MVCDemo.Common
{
public class PartialCacheAttribute : OutputCacheAttribute
{
public PartialCacheAttribute(string cacheProfileName)
{
OutputCacheSettingsSection cacheSettings = (OutputCacheSettingsSection)WebConfigurationManager.GetSection("system.web/caching/outputCacheSettings");
OutputCacheProfile cacheProfile = cacheSettings.OutputCacheProfiles[cacheProfileName];
Duration = cacheProfile.Duration;
VaryByParam = cacheProfile.VaryByParam;
VaryByCustom = cacheProfile.VaryByCustom;
}
}
}
Step 4: Use PartialCacheAttribute on the child action method, and pass it the name of the cache profile in web.config. Please note that, PartialCacheAttribute is in MVCDemo.Common namespace.
[ChildActionOnly]
[PartialCache("1MinuteCache")]
public string GetEmployeeCount()
{
return "Employee Count = " + db.Employees.Count().ToString()
+ "@ " + DateTime.Now.ToString();
}
Suggested Videos
Part 72 - HandleError attribute
Part 73 - OutputCache attribute
Part 74 - CacheProfiles
In this video, we will discuss RequireHttps attribute.
[RequireHttps] attribute forces an unsecured HTTP request to be re-sent over HTTPS. Let's understand [RequireHttps] attribute with an example.
Step 1: Create an asp.net mvc4 application using "Empty" template
Step 2: Add a HomeController. Copy and paste the Login() action method in the HomeController.
[RequireHttps]
public string Login()
{
return "This method should be accessed only using HTTPS protocol";
}
Step 3: Try to navigate to http://localhost/MVCDemo/Home/Login. Notice that you are automatically redirected to https://localhost/MVCDemo/Home/Login. So, [RequireHttps] attribute, forces an HTTP request to be re-sent over HTTPS.

RequireHttps attribute can be applied on a controller as well. In this case, it is applicable for all action methods with in that controller.
Sensitive data such as login credentials, credit card information etc, must always be transmitted using HTTPS. Information transmitted over https is encrypted.
Part 72 - HandleError attribute
Part 73 - OutputCache attribute
Part 74 - CacheProfiles
In this video, we will discuss RequireHttps attribute.
[RequireHttps] attribute forces an unsecured HTTP request to be re-sent over HTTPS. Let's understand [RequireHttps] attribute with an example.
Step 1: Create an asp.net mvc4 application using "Empty" template
Step 2: Add a HomeController. Copy and paste the Login() action method in the HomeController.
[RequireHttps]
public string Login()
{
return "This method should be accessed only using HTTPS protocol";
}
Step 3: Try to navigate to http://localhost/MVCDemo/Home/Login. Notice that you are automatically redirected to https://localhost/MVCDemo/Home/Login. So, [RequireHttps] attribute, forces an HTTP request to be re-sent over HTTPS.

RequireHttps attribute can be applied on a controller as well. In this case, it is applicable for all action methods with in that controller.
Sensitive data such as login credentials, credit card information etc, must always be transmitted using HTTPS. Information transmitted over https is encrypted.
Suggested Videos
Part 73 - OutputCache attribute
Part 74 - CacheProfiles
Part 75 - RequireHttps attribute
In this video, we will discuss ValidateInput attribute. This attribute is used to enable or disable request validation. By default, request validation is enabled in asp.net mvc. Let's understand this with an example.
Step 1: Create an asp.net mvc4 application using Empty template.
Step 2: Add a HomeController. Copy and paste the following code.
public class HomeController : Controller
{
public ActionResult Index()
{
return View();
}
[HttpPost]
public string Index(string comments)
{
return "Your Comments: " + comments;
}
}
Step 3: Add Index.cshtml view. Copy and paste the following code.
<div style="font-family:Arial">
@using (Html.BeginForm())
{
<b>Comments:</b>
<br />
@Html.TextArea("comments")
<br />
<br />
<input type="submit" value="Submit" />
}
</div>
Step 4: Navigate to /Home/Index. Type the following text in the "Comments" textbox and click "Submit".
<h1>Hello</h1>
Notice that, you get an error - A potentially dangerous Request.Form value was detected from the client (comments="<h1>Hello</h1>"). This is because, by default, request validation is turned on in asp.net mvc and does not allow you to submit any HTML, to prevent XSS (Cross site scripting attacks). We discussed XSS in Part 55 & Part 56 of asp.net mvc tutorial.
However, in some cases, you want the user to be able to submit HTML tags like <b>,<u> etc. For this to happen, we need to turn off request validation, by decorating the action method with ValidateInput attribute as shown below.
[HttpPost]
[ValidateInput(false)]
public string Index(string comments)
{
return "Your Comments: " + comments;
}
At this point, you should be able to submit comments, with HTML tags in it.
Part 73 - OutputCache attribute
Part 74 - CacheProfiles
Part 75 - RequireHttps attribute
In this video, we will discuss ValidateInput attribute. This attribute is used to enable or disable request validation. By default, request validation is enabled in asp.net mvc. Let's understand this with an example.
Step 1: Create an asp.net mvc4 application using Empty template.
Step 2: Add a HomeController. Copy and paste the following code.
public class HomeController : Controller
{
public ActionResult Index()
{
return View();
}
[HttpPost]
public string Index(string comments)
{
return "Your Comments: " + comments;
}
}
Step 3: Add Index.cshtml view. Copy and paste the following code.
<div style="font-family:Arial">
@using (Html.BeginForm())
{
<b>Comments:</b>
<br />
@Html.TextArea("comments")
<br />
<br />
<input type="submit" value="Submit" />
}
</div>
Step 4: Navigate to /Home/Index. Type the following text in the "Comments" textbox and click "Submit".
<h1>Hello</h1>
Notice that, you get an error - A potentially dangerous Request.Form value was detected from the client (comments="<h1>Hello</h1>"). This is because, by default, request validation is turned on in asp.net mvc and does not allow you to submit any HTML, to prevent XSS (Cross site scripting attacks). We discussed XSS in Part 55 & Part 56 of asp.net mvc tutorial.
However, in some cases, you want the user to be able to submit HTML tags like <b>,<u> etc. For this to happen, we need to turn off request validation, by decorating the action method with ValidateInput attribute as shown below.
[HttpPost]
[ValidateInput(false)]
public string Index(string comments)
{
return "Your Comments: " + comments;
}
At this point, you should be able to submit comments, with HTML tags in it.
Part 77 - Custom action filters in asp.net mvc
Suggested Videos
Part 74 - CacheProfiles
Part 75 - RequireHttps attribute
Part 76 - ValidateInput attribute
In this video, we will discuss creating custom action filters in asp.net mvc.
Actions are public methods in a controller. Action filters are attributes, that can be applied either on a controller or on a controller action method, which allow us to add pre and post processing logic to the action methods.
So, in simple terms an action filter allow us to execute some custom code, either, just before an action method is executed or immediately after an action method completes execution. We have discussed some of the built-in action filters in the previous sessions of this video series.
Part 70 - Authorize attribute
Part 72 - HandleError attribute
Part 73 - OutputCache attribute
Part 75 - RequireHttps attribute
Part 76 - ValidateInput attribute
Now let's discuss, creating a custom action filter. The custom action filter that we are going to build, should log the following information to a text file.
1. The name of the controller
2. The name of the action method
3. Execution time
4. If there is an exception, log the exception message and the time of the exception.
The output of the text file should be as shown below.

There are 4 types of filters in asp.net mvc.
1. Authorization filters - Implements IAuthorizationFilter. Examples include AuthorizeAttribute and RequireHttpsAttribute. These filters run before any other filter.
2. Action filters - Implement IActionFilter
3. Result filters - Implement IResultFilter. Examples include OutputCacheAttribute.
4. Exception filters - Implement IExceptionFilter. Examples include HandleErrorAttribute.
For detailed explanation of these attributes, please refer to the following MSDN link
http://msdn.microsoft.com/en-us/library/gg416513(v=vs.98).aspx
Step 1: Create an asp.net mvc 4 application using "Empty" template
Step 2: Right click on the project name in solution explorer and add "Data" folder. Add a text file to this folder and name it Data.txt
Step 3: Right click on the project name in solution explorer and add "Common" folder. Add a class file to this folder and name it "TrackExecutionTime.cs". Copy and paste the following code. Notice that our custom filter "TrackExecutionTime" inherits from ActionFilterAttribute and IExceptionFilter. ActionFilterAttribute class implements IActionFilter and IResultFilter.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using System.IO;
namespace MVCDemo.Common
{
public class TrackExecutionTime : ActionFilterAttribute, IExceptionFilter
{
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
string message = "\n" + filterContext.ActionDescriptor.ControllerDescriptor.ControllerName +
" -> " + filterContext.ActionDescriptor.ActionName + " -> OnActionExecuting \t- " +
DateTime.Now.ToString() + "\n";
LogExecutionTime(message);
}
public override void OnActionExecuted(ActionExecutedContext filterContext)
{
string message = "\n" + filterContext.ActionDescriptor.ControllerDescriptor.ControllerName +
" -> " + filterContext.ActionDescriptor.ActionName + " -> OnActionExecuted \t- " +
DateTime.Now.ToString() + "\n";
LogExecutionTime(message);
}
public override void OnResultExecuting(ResultExecutingContext filterContext)
{
string message = filterContext.RouteData.Values["controller"].ToString() +
" -> " + filterContext.RouteData.Values["action"].ToString() +
" -> OnResultExecuting \t- " + DateTime.Now.ToString() + "\n";
LogExecutionTime(message);
}
public override void OnResultExecuted(ResultExecutedContext filterContext)
{
string message = filterContext.RouteData.Values["controller"].ToString() +
" -> " + filterContext.RouteData.Values["action"].ToString() +
" -> OnResultExecuted \t- " + DateTime.Now.ToString() + "\n";
LogExecutionTime(message);
LogExecutionTime("---------------------------------------------------------\n");
}
public void OnException(ExceptionContext filterContext)
{
string message = filterContext.RouteData.Values["controller"].ToString() + " -> " +
filterContext.RouteData.Values["action"].ToString() + " -> " +
filterContext.Exception.Message + " \t- " + DateTime.Now.ToString() + "\n";
LogExecutionTime(message);
LogExecutionTime("---------------------------------------------------------\n");
}
private void LogExecutionTime(string message)
{
File.AppendAllText(HttpContext.Current.Server.MapPath("~/Data/Data.txt"), message);
}
}
}
Step 4: Add a HomeController. Copy and paste the following code.
public class HomeController : Controller
{
[TrackExecutionTime]
public string Index()
{
return "Index Action Invoked";
}
[TrackExecutionTime]
public string Welcome()
{
throw new Exception("Exception ocuured");
}
}
Please Note: TrackExecutionTime class is present in MVCDemo.Common namespace.
Build the application and navigate to /Home/Index and then to /Home/Welcome. Notice that the execution times and the exception details are logged in the text file.
Part 74 - CacheProfiles
Part 75 - RequireHttps attribute
Part 76 - ValidateInput attribute
In this video, we will discuss creating custom action filters in asp.net mvc.
Actions are public methods in a controller. Action filters are attributes, that can be applied either on a controller or on a controller action method, which allow us to add pre and post processing logic to the action methods.
So, in simple terms an action filter allow us to execute some custom code, either, just before an action method is executed or immediately after an action method completes execution. We have discussed some of the built-in action filters in the previous sessions of this video series.
Part 70 - Authorize attribute
Part 72 - HandleError attribute
Part 73 - OutputCache attribute
Part 75 - RequireHttps attribute
Part 76 - ValidateInput attribute
Now let's discuss, creating a custom action filter. The custom action filter that we are going to build, should log the following information to a text file.
1. The name of the controller
2. The name of the action method
3. Execution time
4. If there is an exception, log the exception message and the time of the exception.
The output of the text file should be as shown below.

There are 4 types of filters in asp.net mvc.
1. Authorization filters - Implements IAuthorizationFilter. Examples include AuthorizeAttribute and RequireHttpsAttribute. These filters run before any other filter.
2. Action filters - Implement IActionFilter
3. Result filters - Implement IResultFilter. Examples include OutputCacheAttribute.
4. Exception filters - Implement IExceptionFilter. Examples include HandleErrorAttribute.
For detailed explanation of these attributes, please refer to the following MSDN link
http://msdn.microsoft.com/en-us/library/gg416513(v=vs.98).aspx
Step 1: Create an asp.net mvc 4 application using "Empty" template
Step 2: Right click on the project name in solution explorer and add "Data" folder. Add a text file to this folder and name it Data.txt
Step 3: Right click on the project name in solution explorer and add "Common" folder. Add a class file to this folder and name it "TrackExecutionTime.cs". Copy and paste the following code. Notice that our custom filter "TrackExecutionTime" inherits from ActionFilterAttribute and IExceptionFilter. ActionFilterAttribute class implements IActionFilter and IResultFilter.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using System.IO;
namespace MVCDemo.Common
{
public class TrackExecutionTime : ActionFilterAttribute, IExceptionFilter
{
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
string message = "\n" + filterContext.ActionDescriptor.ControllerDescriptor.ControllerName +
" -> " + filterContext.ActionDescriptor.ActionName + " -> OnActionExecuting \t- " +
DateTime.Now.ToString() + "\n";
LogExecutionTime(message);
}
public override void OnActionExecuted(ActionExecutedContext filterContext)
{
string message = "\n" + filterContext.ActionDescriptor.ControllerDescriptor.ControllerName +
" -> " + filterContext.ActionDescriptor.ActionName + " -> OnActionExecuted \t- " +
DateTime.Now.ToString() + "\n";
LogExecutionTime(message);
}
public override void OnResultExecuting(ResultExecutingContext filterContext)
{
string message = filterContext.RouteData.Values["controller"].ToString() +
" -> " + filterContext.RouteData.Values["action"].ToString() +
" -> OnResultExecuting \t- " + DateTime.Now.ToString() + "\n";
LogExecutionTime(message);
}
public override void OnResultExecuted(ResultExecutedContext filterContext)
{
string message = filterContext.RouteData.Values["controller"].ToString() +
" -> " + filterContext.RouteData.Values["action"].ToString() +
" -> OnResultExecuted \t- " + DateTime.Now.ToString() + "\n";
LogExecutionTime(message);
LogExecutionTime("---------------------------------------------------------\n");
}
public void OnException(ExceptionContext filterContext)
{
string message = filterContext.RouteData.Values["controller"].ToString() + " -> " +
filterContext.RouteData.Values["action"].ToString() + " -> " +
filterContext.Exception.Message + " \t- " + DateTime.Now.ToString() + "\n";
LogExecutionTime(message);
LogExecutionTime("---------------------------------------------------------\n");
}
private void LogExecutionTime(string message)
{
File.AppendAllText(HttpContext.Current.Server.MapPath("~/Data/Data.txt"), message);
}
}
}
Step 4: Add a HomeController. Copy and paste the following code.
public class HomeController : Controller
{
[TrackExecutionTime]
public string Index()
{
return "Index Action Invoked";
}
[TrackExecutionTime]
public string Welcome()
{
throw new Exception("Exception ocuured");
}
}
Please Note: TrackExecutionTime class is present in MVCDemo.Common namespace.
Build the application and navigate to /Home/Index and then to /Home/Welcome. Notice that the execution times and the exception details are logged in the text file.
Part 78 - Different types of ActionResult in asp.net mvc
Suggested Videos
Part 75 - RequireHttps attribute
Part 76 - ValidateInput attribute
Part 77 - Custom action filters
In this video, we will discuss different types of ActionResult objects that can be returned by an action method.
The following is the signature of a typical action method in a controller. Notice that, the return type is ActionResult. ActionResult is an abstract class and has several sub types.
public ActionResult Index()
{
return View();
}
Here is the list of all sub-types of ActionResult.

I have used a tool called ILSpy, to list all the sub-types of ActionResult. To use the tool yourself, here are the steps
1. Navigate to http://ilspy.net
2. Click on "Download Binaries" button, and extract them to a folder.
3. Run ILSpy.exe which can be found in the folder, where you have extracted the binaries.
4. Click on File - Open From GAC
5. Type "System.Web.Mvc" in the search box. Select the Assembly and click Open
6. At this point System.Web.Mvc assmbly should be loaded into ILSpy. Expand System.Web.Mvc, then expand ActionResult and then expand "Derived Types". You should now be able to see all the derived types.
Why do we have so many sub-types?
An action method in a controller, can return a wide range of objects. For example, an action method can return
1. ViewResult
2. PartialViewResult
3. JsonResult
4. RedirectResult etc..
What should be the return type of an action method - ActionResult or specific derived type?
It's a good practise to return specific sub-types, but, if different paths of the action method returns different subtypes, then I would return an ActionResult object. An example is shown below.
public ActionResult Index()
{
if (Your_Condition)
return View(); // returns ViewResult object
else
return Json("Data"); // returns JsonResult object
}
The following table lists
1. Action Result Sub Types
2. The purpose of each sub-type
3. The helper methods used to retrun the specific sub-type

Part 75 - RequireHttps attribute
Part 76 - ValidateInput attribute
Part 77 - Custom action filters
In this video, we will discuss different types of ActionResult objects that can be returned by an action method.
The following is the signature of a typical action method in a controller. Notice that, the return type is ActionResult. ActionResult is an abstract class and has several sub types.
public ActionResult Index()
{
return View();
}
Here is the list of all sub-types of ActionResult.

I have used a tool called ILSpy, to list all the sub-types of ActionResult. To use the tool yourself, here are the steps
1. Navigate to http://ilspy.net
2. Click on "Download Binaries" button, and extract them to a folder.
3. Run ILSpy.exe which can be found in the folder, where you have extracted the binaries.
4. Click on File - Open From GAC
5. Type "System.Web.Mvc" in the search box. Select the Assembly and click Open
6. At this point System.Web.Mvc assmbly should be loaded into ILSpy. Expand System.Web.Mvc, then expand ActionResult and then expand "Derived Types". You should now be able to see all the derived types.
Why do we have so many sub-types?
An action method in a controller, can return a wide range of objects. For example, an action method can return
1. ViewResult
2. PartialViewResult
3. JsonResult
4. RedirectResult etc..
What should be the return type of an action method - ActionResult or specific derived type?
It's a good practise to return specific sub-types, but, if different paths of the action method returns different subtypes, then I would return an ActionResult object. An example is shown below.
public ActionResult Index()
{
if (Your_Condition)
return View(); // returns ViewResult object
else
return Json("Data"); // returns JsonResult object
}
The following table lists
1. Action Result Sub Types
2. The purpose of each sub-type
3. The helper methods used to retrun the specific sub-type

Suggested Videos
Part 76 - ValidateInput attribute
Part 77 - Custom action filters
Paty 78 - Different types of ActionResult in asp.net mvc
In this video, we will discuss Areas.
When you create a new asp.net mvc application, the following folders are created with in the root directory.
1. Models
2. Views
3. Controllers
This structure is fine for simple applications, but when your application gets big and complex, maintaining your Models, Views and Controllers can get complicated.
The structure of a complex asp.net mvc application can be very easily maintained using areas. So, in short areas are introduced in asp.net mvc 2, that allow us to breakdown a large complex application into a several small sections called areas. These areas can have their own set of
1. Models
2. Views
3. Controllers
4. Routes
Let's understand this with an example. Let's say, we are building a Job Portal. It's common for a typical job portal to have the following functional areas.
Employee Area - This functional area allows a job seeker to create their profile, upload resume, and perform job search.
Employer Area - This functional area allows a job provider to create employer profile, upload jobs, and search for suitable candidates.
Administrator Area - This functional area allows an administrator to configure the site and mantain.
To create an area in an MVC application
1. Right click on the project name in Solution Explorer and select Add => Area
2. Provide a meaningful name. For example "Employee" and click Add
At this point, "Areas" folder will be created, and with in this, a folder for Employee area will be added. You can add as many areas as you want.
In a similar fashion, add areas for Employer and Admin. At this point, your solution explorer should look as shown below. Notice the Areas folder.

Notice that in each area folder (Employee, Employer and Admin), you have a set of Models, Views and Controllers folders. Also, there is "AreaRegistration.cs" file, which contains the code to register a route for the area.
Now navigate to Global.asax.cs file and notice Application_Start(). With in this method there is code to register all areas in your application.
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
WebApiConfig.Register(GlobalConfiguration.Configuration);
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
RouteConfig.RegisterRoutes(RouteTable.Routes);
}
At this point Add "HomeController" to the following areas. Notice that we can have a HomeController(Controller with the same) in Employee, Employer, Admin and MainArea.
1. Employee
2. Employer
3. Admin
4. Main Area
At this point, we have Index() action method in all of the HomeControllers.
public ActionResult Index()
{
return View();
}
Now Add Index view to all the areas. Copy and paste the following HTML in respective Index views.
Main Area: <h1>Main Area Index View</h1>
Employee Area: <h1>Employee Area Index View</h1>
Employer Area: <h1>Employer Area Index View</h1>
Admin Area: <h1>Admin Area Index View</h1>
At this point, build the application, and navigate to http://localhost/MVCDemo. You will get an error
Multiple types were found that match the controller named 'Home'. This can happen if the route that services this request ('{controller}/{action}/{id}') does not specify namespaces to search for a controller that matches the request. If this is the case, register this route by calling an overload of the 'MapRoute' method that takes a 'namespaces' parameter.
The request for 'Home' has found the following matching controllers:
MVCDemo.Controllers.HomeController
MVCDemo.Areas.Admin.Controllers.HomeController
MVCDemo.Areas.Employee.Controllers.HomeController
MVCDemo.Areas.Employer.Controllers.HomeController
To fix this change RegisterRoutes() method in RouteConfig.cs file in App_start folder. Notice that we are passing the namespace of the HomeController in the Main area using namespace parameter.
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional },
namespaces: new [] { "MVCDemo.Controllers" }
);
}
Now, if you navigate to http://localhost/MVCDemo/Employee, you will get an error - The resource cannot be found.
To fix this, change RegisterArea() area method in EmployeeAreaRegistration.cs file in Employee folder as shown below. Notice that we are setting HomeController as the default controller
public override void RegisterArea(AreaRegistrationContext context)
{
context.MapRoute(
"Employee_default",
"Employee/{controller}/{action}/{id}",
new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
}
Navigating to http://localhost/MVCDemo/Employee may throw a compilation error related to System.Web.Optimization. If you get this error follow the steps below.
1. In Visual Studio, click Tools - Library PAckage Manager - Package Manager Console
2. In the Package Manager Console window, type the following command and press enter
Install-Package Microsoft.Web.Optimization -Pre
When we are building links using ActionLink() html helper to navigate between areas, we need to specify area name as shown below. Copy and paste the following code in all the Index views in all the areas and you will be able to navigate between areas when you click on the respective links.
<table border="1">
<tr>
<td>
<b>Links</b>
</td>
</tr>
<tr>
<td>
@Html.ActionLink("Main Area Home Page", "Index", "Home", new { area = "" }, null)
</td>
</tr>
<tr>
<td>
@Html.ActionLink("Employee Area Home Page", "Index", "Home", new { area = "Employee" }, null)
</td>
</tr>
<tr>
<td>
@Html.ActionLink("Employer Area Home Page", "Index", "Home", new { area = "Employer" }, null)
</td>
</tr>
<tr>
<td>
@Html.ActionLink("Admin Area Home Page", "Index", "Home", new { area = "Admin" }, null)
</td>
</tr>
</table>
Part 76 - ValidateInput attribute
Part 77 - Custom action filters
Paty 78 - Different types of ActionResult in asp.net mvc
In this video, we will discuss Areas.
When you create a new asp.net mvc application, the following folders are created with in the root directory.
1. Models
2. Views
3. Controllers
This structure is fine for simple applications, but when your application gets big and complex, maintaining your Models, Views and Controllers can get complicated.
The structure of a complex asp.net mvc application can be very easily maintained using areas. So, in short areas are introduced in asp.net mvc 2, that allow us to breakdown a large complex application into a several small sections called areas. These areas can have their own set of
1. Models
2. Views
3. Controllers
4. Routes
Let's understand this with an example. Let's say, we are building a Job Portal. It's common for a typical job portal to have the following functional areas.
Employee Area - This functional area allows a job seeker to create their profile, upload resume, and perform job search.
Employer Area - This functional area allows a job provider to create employer profile, upload jobs, and search for suitable candidates.
Administrator Area - This functional area allows an administrator to configure the site and mantain.
To create an area in an MVC application
1. Right click on the project name in Solution Explorer and select Add => Area
2. Provide a meaningful name. For example "Employee" and click Add
At this point, "Areas" folder will be created, and with in this, a folder for Employee area will be added. You can add as many areas as you want.
In a similar fashion, add areas for Employer and Admin. At this point, your solution explorer should look as shown below. Notice the Areas folder.

Notice that in each area folder (Employee, Employer and Admin), you have a set of Models, Views and Controllers folders. Also, there is "AreaRegistration.cs" file, which contains the code to register a route for the area.
Now navigate to Global.asax.cs file and notice Application_Start(). With in this method there is code to register all areas in your application.
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
WebApiConfig.Register(GlobalConfiguration.Configuration);
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
RouteConfig.RegisterRoutes(RouteTable.Routes);
}
At this point Add "HomeController" to the following areas. Notice that we can have a HomeController(Controller with the same) in Employee, Employer, Admin and MainArea.
1. Employee
2. Employer
3. Admin
4. Main Area
At this point, we have Index() action method in all of the HomeControllers.
public ActionResult Index()
{
return View();
}
Now Add Index view to all the areas. Copy and paste the following HTML in respective Index views.
Main Area: <h1>Main Area Index View</h1>
Employee Area: <h1>Employee Area Index View</h1>
Employer Area: <h1>Employer Area Index View</h1>
Admin Area: <h1>Admin Area Index View</h1>
At this point, build the application, and navigate to http://localhost/MVCDemo. You will get an error
Multiple types were found that match the controller named 'Home'. This can happen if the route that services this request ('{controller}/{action}/{id}') does not specify namespaces to search for a controller that matches the request. If this is the case, register this route by calling an overload of the 'MapRoute' method that takes a 'namespaces' parameter.
The request for 'Home' has found the following matching controllers:
MVCDemo.Controllers.HomeController
MVCDemo.Areas.Admin.Controllers.HomeController
MVCDemo.Areas.Employee.Controllers.HomeController
MVCDemo.Areas.Employer.Controllers.HomeController
To fix this change RegisterRoutes() method in RouteConfig.cs file in App_start folder. Notice that we are passing the namespace of the HomeController in the Main area using namespace parameter.
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional },
namespaces: new [] { "MVCDemo.Controllers" }
);
}
Now, if you navigate to http://localhost/MVCDemo/Employee, you will get an error - The resource cannot be found.
To fix this, change RegisterArea() area method in EmployeeAreaRegistration.cs file in Employee folder as shown below. Notice that we are setting HomeController as the default controller
public override void RegisterArea(AreaRegistrationContext context)
{
context.MapRoute(
"Employee_default",
"Employee/{controller}/{action}/{id}",
new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
}
Navigating to http://localhost/MVCDemo/Employee may throw a compilation error related to System.Web.Optimization. If you get this error follow the steps below.
1. In Visual Studio, click Tools - Library PAckage Manager - Package Manager Console
2. In the Package Manager Console window, type the following command and press enter
Install-Package Microsoft.Web.Optimization -Pre
When we are building links using ActionLink() html helper to navigate between areas, we need to specify area name as shown below. Copy and paste the following code in all the Index views in all the areas and you will be able to navigate between areas when you click on the respective links.
<table border="1">
<tr>
<td>
<b>Links</b>
</td>
</tr>
<tr>
<td>
@Html.ActionLink("Main Area Home Page", "Index", "Home", new { area = "" }, null)
</td>
</tr>
<tr>
<td>
@Html.ActionLink("Employee Area Home Page", "Index", "Home", new { area = "Employee" }, null)
</td>
</tr>
<tr>
<td>
@Html.ActionLink("Employer Area Home Page", "Index", "Home", new { area = "Employer" }, null)
</td>
</tr>
<tr>
<td>
@Html.ActionLink("Admin Area Home Page", "Index", "Home", new { area = "Admin" }, null)
</td>
</tr>
</table>
Suggested Videos
Part 77 - Custom action filters
Paty 78 - Different types of ActionResult in asp.net mvc
Part 79 - Areas in asp.net mvc
In this video, we will discuss using StringLength attribute. This attribute is present in System.ComponentModel.DataAnnotations namespace and is used to enforce minimum and maximum length of characters that are allowed in a data field. Let's understand this with an example.
We will be using table tblEmployee for this demo.
Create table tblEmployee
(
Id int primary key identity(1,1),
Name nvarchar(50),
Email nvarchar(50),
Age int,
Gender nvarchar(50)
)
Insert into tblEmployee values('Sara Nan', 'Sara.Nani@test.com', 30, 'Female')
Insert into tblEmployee values('James Histo', 'James.Histo@test.com', 33, 'Male' )
Insert into tblEmployee values('Mary Jane', 'Mary.Jane@test.com', 28, 'Female' )
Insert into tblEmployee values('Paul Sensit', 'Paul.Sensit@test.com', 29, 'Male' )
Generate ADO.NET entity data model for table tblEmployee. Change the entity name from tblEmployee to Employee. Save and build the project.
Right click on the "Controllers" folder and select Add - Controller. Set
Name = HomeController
Template = MVC controller with read/write actions and views, using Entity Framework
Model class = Employee(MVCDemo.Models)
Data Context Class = EmployeeContext(MVCDemo.Models)
Views = Razor
To validate data, use validation attributes that are found in System.ComponentModel.DataAnnotations namespace. It is not a good idea, to add these validation attributes to the properties of auto-generated "Employee" class, as our changes will be lost, if the class is auto-generated again.
So, let's create another partial "Employee" class, and decorate that class with the validation attributes. Right click on the "Models" folder and add Employee.cs class file. Copy and paste the following code.
using System.ComponentModel.DataAnnotations;
namespace MVCDemo.Models
{
[MetadataType(typeof(EmployeeMetaData))]
public partial class Employee
{
}
public class EmployeeMetaData
{
[StringLength(10, MinimumLength = 5)]
[Required]
public string Name { get; set; }
}
}
Notice that, we have decorated "Name" property with "StringLength" attribute and specified Minimum and Maximum length properties. We also used [Required] attribute. So, at this point Name property is required and should be between 5 and 10 characters.
Points to remember:
1. [StringLength] attribute is present in System.ComponentModel.DataAnnotations namespace.
2. [StringLength] attribute verifies that a string is of certain length, but does not enforce that the property is REQUIRED. If you want to enforce that the property is required use [Required] attribute.
We will discuss the following attributes in our upcoming video sessions.
RegularExpression
Range
Part 77 - Custom action filters
Paty 78 - Different types of ActionResult in asp.net mvc
Part 79 - Areas in asp.net mvc
In this video, we will discuss using StringLength attribute. This attribute is present in System.ComponentModel.DataAnnotations namespace and is used to enforce minimum and maximum length of characters that are allowed in a data field. Let's understand this with an example.
We will be using table tblEmployee for this demo.
Create table tblEmployee
(
Id int primary key identity(1,1),
Name nvarchar(50),
Email nvarchar(50),
Age int,
Gender nvarchar(50)
)
Insert into tblEmployee values('Sara Nan', 'Sara.Nani@test.com', 30, 'Female')
Insert into tblEmployee values('James Histo', 'James.Histo@test.com', 33, 'Male' )
Insert into tblEmployee values('Mary Jane', 'Mary.Jane@test.com', 28, 'Female' )
Insert into tblEmployee values('Paul Sensit', 'Paul.Sensit@test.com', 29, 'Male' )
Generate ADO.NET entity data model for table tblEmployee. Change the entity name from tblEmployee to Employee. Save and build the project.
Right click on the "Controllers" folder and select Add - Controller. Set
Name = HomeController
Template = MVC controller with read/write actions and views, using Entity Framework
Model class = Employee(MVCDemo.Models)
Data Context Class = EmployeeContext(MVCDemo.Models)
Views = Razor
To validate data, use validation attributes that are found in System.ComponentModel.DataAnnotations namespace. It is not a good idea, to add these validation attributes to the properties of auto-generated "Employee" class, as our changes will be lost, if the class is auto-generated again.
So, let's create another partial "Employee" class, and decorate that class with the validation attributes. Right click on the "Models" folder and add Employee.cs class file. Copy and paste the following code.
using System.ComponentModel.DataAnnotations;
namespace MVCDemo.Models
{
[MetadataType(typeof(EmployeeMetaData))]
public partial class Employee
{
}
public class EmployeeMetaData
{
[StringLength(10, MinimumLength = 5)]
[Required]
public string Name { get; set; }
}
}
Notice that, we have decorated "Name" property with "StringLength" attribute and specified Minimum and Maximum length properties. We also used [Required] attribute. So, at this point Name property is required and should be between 5 and 10 characters.
Points to remember:
1. [StringLength] attribute is present in System.ComponentModel.DataAnnotations namespace.
2. [StringLength] attribute verifies that a string is of certain length, but does not enforce that the property is REQUIRED. If you want to enforce that the property is required use [Required] attribute.
We will discuss the following attributes in our upcoming video sessions.
RegularExpression
Range
Suggested Videos
Part 78 - Different types of ActionResult in asp.net mvc
Part 79 - Areas in asp.net mvc
Part 80 - StringLength attribute
RangeAttribute checks if the value of a data field is within a specified range of values. We will be working with the example, that we started in Part 80. Please watch Part 80, before proceeding.
When you navigate to /Home/Edit/1, notice that we don't have validation on Age field. If you enter 5000 as the age and click Save, the date gets saved. Obviously an employee having 5000 years as the age is not practical. So, let's validate Age field, and enforce users to enter a value between 1 and 100. To achieve this RangeAttribute can be used.
Make the following change to the Employee class in Employee.cs file in Models folder. Notice that, we are using RangeAttribute, and have set minimum and maximum as 1 and 100 respectively.
public class EmployeeMetaData
{
[StringLength(10, MinimumLength = 5)]
[Required]
public string Name { get; set; }
[Range(1, 100)]
public int Age { get; set; }
}
At this point, we should not be able to enter any values outside the range of 1 and 100 for Age field.
Range attribute can also be used to validate DateTime fields. Let's now discuss using Range attribute with DateTime fields.
At the moment our Employee class does not have any DateTime field. Let's add HireDate column to table tblEmployee. Use the sql script below to alter the table.
Alter table tblEmployee
Add HireDate Date
SQL script to update the existing employee records:
Update tblEmployee Set HireDate='2009-08-20' where ID=1
Update tblEmployee Set HireDate='2008-07-13' where ID=2
Update tblEmployee Set HireDate='2005-11-11' where ID=3
Update tblEmployee Set HireDate='2007-10-23' where ID=4
Update the ADO.NET data model.
1. In the Solution Explorer, double click on SampleDataModel.edmx file in Models folder.
2. Right click on "Employee" model and select "Update Model from database" option
3. Click on "Refresh" tab on "Update Wizard"
4. Expand "Tables" and select "tblEmployee" table and click "Finish.
5. These steps should add HireDate property to the autogenerated Employee entity class
Build the solution to compile Employee entity class.
Copy and paste the following 2 DIV tags in Edit.cshtml view, just above the "Save" button.
<div class="editor-label">
@Html.LabelFor(model => model.HireDate)
</div>
<div class="editor-field">
@Html.EditorFor(model => model.HireDate)
@Html.ValidationMessageFor(model => model.HireDate)
</div>
Make the following change to the Employee class in Employee.cs file in Models folder. Notice that, we are passing DateTime as the type and specifying the minimum and maximum values for HireDate. We are also using DisplayFormat attribute, so that only date part of DateTime is displayed in the Edit view.
public class EmployeeMetaData
{
[StringLength(10, MinimumLength = 5)]
[Required]
public string Name { get; set; }
[Range(1, 100)]
public int Age { get; set; }
[Range(typeof(DateTime), "01/01/2000", "01/01/2010")]
[DisplayFormat(DataFormatString = "{0:d}", ApplyFormatInEditMode = true)]
public DateTime HireDate { get; set; }
}
At this point, we should not be able to enter any values outside the range of "01/01/2000" and "01/01/2010" for HireDate field.
However, when the Range attribute is used with DateTime fields, the client side validation does not work as expected. We will discuss this in a later video session.
Part 78 - Different types of ActionResult in asp.net mvc
Part 79 - Areas in asp.net mvc
Part 80 - StringLength attribute
RangeAttribute checks if the value of a data field is within a specified range of values. We will be working with the example, that we started in Part 80. Please watch Part 80, before proceeding.
When you navigate to /Home/Edit/1, notice that we don't have validation on Age field. If you enter 5000 as the age and click Save, the date gets saved. Obviously an employee having 5000 years as the age is not practical. So, let's validate Age field, and enforce users to enter a value between 1 and 100. To achieve this RangeAttribute can be used.
Make the following change to the Employee class in Employee.cs file in Models folder. Notice that, we are using RangeAttribute, and have set minimum and maximum as 1 and 100 respectively.
public class EmployeeMetaData
{
[StringLength(10, MinimumLength = 5)]
[Required]
public string Name { get; set; }
[Range(1, 100)]
public int Age { get; set; }
}
At this point, we should not be able to enter any values outside the range of 1 and 100 for Age field.
Range attribute can also be used to validate DateTime fields. Let's now discuss using Range attribute with DateTime fields.
At the moment our Employee class does not have any DateTime field. Let's add HireDate column to table tblEmployee. Use the sql script below to alter the table.
Alter table tblEmployee
Add HireDate Date
SQL script to update the existing employee records:
Update tblEmployee Set HireDate='2009-08-20' where ID=1
Update tblEmployee Set HireDate='2008-07-13' where ID=2
Update tblEmployee Set HireDate='2005-11-11' where ID=3
Update tblEmployee Set HireDate='2007-10-23' where ID=4
Update the ADO.NET data model.
1. In the Solution Explorer, double click on SampleDataModel.edmx file in Models folder.
2. Right click on "Employee" model and select "Update Model from database" option
3. Click on "Refresh" tab on "Update Wizard"
4. Expand "Tables" and select "tblEmployee" table and click "Finish.
5. These steps should add HireDate property to the autogenerated Employee entity class
Build the solution to compile Employee entity class.
Copy and paste the following 2 DIV tags in Edit.cshtml view, just above the "Save" button.
<div class="editor-label">
@Html.LabelFor(model => model.HireDate)
</div>
<div class="editor-field">
@Html.EditorFor(model => model.HireDate)
@Html.ValidationMessageFor(model => model.HireDate)
</div>
Make the following change to the Employee class in Employee.cs file in Models folder. Notice that, we are passing DateTime as the type and specifying the minimum and maximum values for HireDate. We are also using DisplayFormat attribute, so that only date part of DateTime is displayed in the Edit view.
public class EmployeeMetaData
{
[StringLength(10, MinimumLength = 5)]
[Required]
public string Name { get; set; }
[Range(1, 100)]
public int Age { get; set; }
[Range(typeof(DateTime), "01/01/2000", "01/01/2010")]
[DisplayFormat(DataFormatString = "{0:d}", ApplyFormatInEditMode = true)]
public DateTime HireDate { get; set; }
}
At this point, we should not be able to enter any values outside the range of "01/01/2000" and "01/01/2010" for HireDate field.
However, when the Range attribute is used with DateTime fields, the client side validation does not work as expected. We will discuss this in a later video session.
Part 82 - Creating custom validation attribute in asp.net mvc
Suggested Videos
Part 79 - Areas in asp.net mvc
Part 80 - StringLength attribute
Part 81 - Range attribute
In this video, we will discuss, creating custom validation attribute in asp.net mvc. We will be working with the example, that we started in Part 80. Please watch Part 80, and Part 81 before proceeding.
At the moment, any value outside the range of "01/01/2000" and "01/01/2010" for HireDate filed, will raise a validation error.
[Range(typeof(DateTime), "01/01/2000", "01/01/2010")]
[DisplayFormat(DataFormatString = "{0:d}", ApplyFormatInEditMode = true)]
public DateTime HireDate { get; set; }
But, let's say, we want the end date to be today's date instead of the hardcode "01/01/2010" value. To achieve this we would be tempted to use DateTime.Now.ToShortDateString() as shown below.
[Range(typeof(DateTime), "01/01/2000", DateTime.Now.ToShortDateString())]
[DisplayFormat(DataFormatString = "{0:d}", ApplyFormatInEditMode = true)]
public DateTime HireDate { get; set; }
At this point, if you compile, you will get an error - An attribute argument must be a constant expression, typeof expression or array creation expression of an attribute parameter type.
To fix this, we can create a custom DateRangeAttribute. Here are the steps
1. Right click on the project name in solution explorer, and add "Common" folder.
2. Right click on the "Common" folder and add a class file with name = DateRangeAttribute.cs
3. Copy and paste the following code in DateRangeAttribute.cs class file.
using System;
using System.ComponentModel.DataAnnotations;
namespace MVCDemo.Common
{
public class DateRangeAttribute : RangeAttribute
{
public DateRangeAttribute(string minimumValue)
: base(typeof(DateTime), minimumValue, DateTime.Now.ToShortDateString())
{
}
}
}
4. Finally decorate "HireDate" property with our custom DateRangeAttribute as shown below. Notice that, we are only passing the minimum date value. Maximum date value will be today's date. Please note, DateRangeAttribute is present in MVCDemo.Common namespace.
[DateRange("01/01/2000")]
[DisplayFormat(DataFormatString = "{0:d}", ApplyFormatInEditMode = true)]
public DateTime HireDate { get; set; }
Let's now look at another example of creating a custom validation attribute. Let's say our business rules have changed, and the HireDate property should allow any valid date that is <= Today's Date. This means, there is no minimum value restriction and the maximum value should be less than or equal to Today's date. To achieve this, let's add another custom validation attribute. Here are the steps
1. Right click on the "Common" folder and add a class file with name = CurrentDateAttribute.cs
2. Copy and paste the following code in CurrentDateAttribute.cs class file.
using System;
using System.ComponentModel.DataAnnotations;
namespace MVCDemo.Common
{
public class CurrentDateAttribute : ValidationAttribute
{
public override bool IsValid(object value)
{
DateTime dateTime = Convert.ToDateTime(value);
return dateTime <= DateTime.Now;
}
}
}
3. Decorate "HireDate" property with our custom CurrentDateAttribute as shown below.
[CurrentDate]
[DisplayFormat(DataFormatString = "{0:d}", ApplyFormatInEditMode = true)]
public DateTime HireDate { get; set; }
Please note that the validation error message can be customised using named parameter "ErrorMessage" as shown below.
[CurrentDate(ErrorMessage = "Hire Date must be less than or equal to Today's Date")]
[DisplayFormat(DataFormatString = "{0:d}", ApplyFormatInEditMode = true)]
public DateTime HireDate { get; set; }
Part 79 - Areas in asp.net mvc
Part 80 - StringLength attribute
Part 81 - Range attribute
In this video, we will discuss, creating custom validation attribute in asp.net mvc. We will be working with the example, that we started in Part 80. Please watch Part 80, and Part 81 before proceeding.
At the moment, any value outside the range of "01/01/2000" and "01/01/2010" for HireDate filed, will raise a validation error.
[Range(typeof(DateTime), "01/01/2000", "01/01/2010")]
[DisplayFormat(DataFormatString = "{0:d}", ApplyFormatInEditMode = true)]
public DateTime HireDate { get; set; }
But, let's say, we want the end date to be today's date instead of the hardcode "01/01/2010" value. To achieve this we would be tempted to use DateTime.Now.ToShortDateString() as shown below.
[Range(typeof(DateTime), "01/01/2000", DateTime.Now.ToShortDateString())]
[DisplayFormat(DataFormatString = "{0:d}", ApplyFormatInEditMode = true)]
public DateTime HireDate { get; set; }
At this point, if you compile, you will get an error - An attribute argument must be a constant expression, typeof expression or array creation expression of an attribute parameter type.
To fix this, we can create a custom DateRangeAttribute. Here are the steps
1. Right click on the project name in solution explorer, and add "Common" folder.
2. Right click on the "Common" folder and add a class file with name = DateRangeAttribute.cs
3. Copy and paste the following code in DateRangeAttribute.cs class file.
using System;
using System.ComponentModel.DataAnnotations;
namespace MVCDemo.Common
{
public class DateRangeAttribute : RangeAttribute
{
public DateRangeAttribute(string minimumValue)
: base(typeof(DateTime), minimumValue, DateTime.Now.ToShortDateString())
{
}
}
}
4. Finally decorate "HireDate" property with our custom DateRangeAttribute as shown below. Notice that, we are only passing the minimum date value. Maximum date value will be today's date. Please note, DateRangeAttribute is present in MVCDemo.Common namespace.
[DateRange("01/01/2000")]
[DisplayFormat(DataFormatString = "{0:d}", ApplyFormatInEditMode = true)]
public DateTime HireDate { get; set; }
Let's now look at another example of creating a custom validation attribute. Let's say our business rules have changed, and the HireDate property should allow any valid date that is <= Today's Date. This means, there is no minimum value restriction and the maximum value should be less than or equal to Today's date. To achieve this, let's add another custom validation attribute. Here are the steps
1. Right click on the "Common" folder and add a class file with name = CurrentDateAttribute.cs
2. Copy and paste the following code in CurrentDateAttribute.cs class file.
using System;
using System.ComponentModel.DataAnnotations;
namespace MVCDemo.Common
{
public class CurrentDateAttribute : ValidationAttribute
{
public override bool IsValid(object value)
{
DateTime dateTime = Convert.ToDateTime(value);
return dateTime <= DateTime.Now;
}
}
}
3. Decorate "HireDate" property with our custom CurrentDateAttribute as shown below.
[CurrentDate]
[DisplayFormat(DataFormatString = "{0:d}", ApplyFormatInEditMode = true)]
public DateTime HireDate { get; set; }
Please note that the validation error message can be customised using named parameter "ErrorMessage" as shown below.
[CurrentDate(ErrorMessage = "Hire Date must be less than or equal to Today's Date")]
[DisplayFormat(DataFormatString = "{0:d}", ApplyFormatInEditMode = true)]
public DateTime HireDate { get; set; }
Suggested Videos
Part 80 - StringLength attribute
Part 81 - Range attribute
Part 82 - Creating custom validation attribute
Regular expression attribute is great for pattern matching validation. Let's understand using Regular expression attribute with an example. We will be continuing with the example that we started in Part 80 of the asp.net mvc tutorial.
Here is the requirement for validating Name property
1. Name can contain first and last name with a single space.
2. Last name is optional. If last name is not present, then there shouldn't be any space after the first name.
3. Only upper and lower case alphabets are allowed.
This requirement can be very easily met using RegularExpression attribute. In Employee.cs class file, decorate Name property with RegularExpression attribute.
[RegularExpression(@"^(([A-za-z]+[\s]{1}[A-za-z]+)|([A-Za-z]+))$")]
public string Name { get; set; }
Notice that, we are passing regular expression string to the attribute constructor. Regular expressions are great for pattern matching and ensures that, the value for name property is in the format that we want. Also, notice that we are using a verbatim literal(@ symbol) string, as we don't want escape sequences to be processed. We discussed verbatim literal in Part 4 of C# tutorial.
Understanding and writing regular expressions is beyond the scope of this video. If you are interested in learning to write regular expressions, here is a link from MSDN
http://msdn.microsoft.com/en-us/library/az24scfc.aspx
The following website is very helpful, for writing and testing regular expressions. This website also contains commonly used regular expressions. Infact, I have picked up the regular expression for validating Name property from here.
http://gskinner.com/RegExr/
Let's discuss another example of using validation attribute. A valid internet email address should have an @ and a DOT symbol in it. To match this pattern, use the following regular expression.
^[\w-\._\+%]+@(?:[\w-]+\.)+[\w]{2,6}$
In Employee.cs class file, decorate Email property with RegularExpression attribute as shown below.
[RegularExpression(@"^[\w-\._\+%]+@(?:[\w-]+\.)+[\w]{2,6}$", ErrorMessage = "Please enter a valid email address")]
public string Email { get; set; }
Part 80 - StringLength attribute
Part 81 - Range attribute
Part 82 - Creating custom validation attribute
Regular expression attribute is great for pattern matching validation. Let's understand using Regular expression attribute with an example. We will be continuing with the example that we started in Part 80 of the asp.net mvc tutorial.
Here is the requirement for validating Name property
1. Name can contain first and last name with a single space.
2. Last name is optional. If last name is not present, then there shouldn't be any space after the first name.
3. Only upper and lower case alphabets are allowed.
This requirement can be very easily met using RegularExpression attribute. In Employee.cs class file, decorate Name property with RegularExpression attribute.
[RegularExpression(@"^(([A-za-z]+[\s]{1}[A-za-z]+)|([A-Za-z]+))$")]
public string Name { get; set; }
Notice that, we are passing regular expression string to the attribute constructor. Regular expressions are great for pattern matching and ensures that, the value for name property is in the format that we want. Also, notice that we are using a verbatim literal(@ symbol) string, as we don't want escape sequences to be processed. We discussed verbatim literal in Part 4 of C# tutorial.
Understanding and writing regular expressions is beyond the scope of this video. If you are interested in learning to write regular expressions, here is a link from MSDN
http://msdn.microsoft.com/en-us/library/az24scfc.aspx
The following website is very helpful, for writing and testing regular expressions. This website also contains commonly used regular expressions. Infact, I have picked up the regular expression for validating Name property from here.
http://gskinner.com/RegExr/
Let's discuss another example of using validation attribute. A valid internet email address should have an @ and a DOT symbol in it. To match this pattern, use the following regular expression.
^[\w-\._\+%]+@(?:[\w-]+\.)+[\w]{2,6}$
In Employee.cs class file, decorate Email property with RegularExpression attribute as shown below.
[RegularExpression(@"^[\w-\._\+%]+@(?:[\w-]+\.)+[\w]{2,6}$", ErrorMessage = "Please enter a valid email address")]
public string Email { get; set; }
Part 84 - Compare attribute in asp.net mvc
Suggested
Videos Part 81 - Range attribute
Part 82 - Creating custom validation attribute
Part 83 - RegularExpression attribute
Compare attribute is used to compare 2 properties of a model. Comparing email addresses and passwords is the common use case of Compare attribute. Let's understand using Compare attribute with an example. We will be continuing with the example, that we discussed in Part 83.
To ensure that the user has typed the correct email, let's include "Confirm Email" field on the "Edit" view. To achieve this, add "ConfirmEmail" property in "Employee" class in Employee.cs class file that is present in "Models" folder.
public partial class Employee
{
public string ConfirmEmail { get; set; }
}
At this point you may get this question. Why are we not adding this property to EmployeeMetaData class. This is because EmployeeMetaData class, is used to associate metadata for the properties that are already present in the auto-generated Employee class. The auto-generated Employee class is present in SampleDataModel.Designer.cs file in Models folder. ConfirmEmail property does not exist in auto-generated Employee class. It is a new property that we want to add to Employee model class. ConfirmEmail property is going to be used only for validation. We will not be saving the value of this property to the database table. We will be stroing Emial property value to the database.
Build the solution, so that the Employee class is compiled.
Copy and paste the following 2 div tags, to add ConfirmEmail field to the Edit View.
<div class="editor-label">
@Html.LabelFor(model => model.ConfirmEmail)
</div>
<div class="editor-field">
@Html.EditorFor(model => model.ConfirmEmail)
@Html.ValidationMessageFor(model => model.ConfirmEmail)
</div>
Finally, decorate ConfirmEmail property in Employee class with Compare attribute. Most of the validation attributes are present in System.ComponentModel.DataAnnotations namespace, but Compare attribute is present in System.Web.Mvc namespace.
public partial class Employee
{
[Compare("Email")]
public string ConfirmEmail { get; set; }
}
At this point, this confirm attribute will ensure Email and ConfirmEmail properties have the same values. If they don't, then a validation error message is displayed.
No comments:
Post a Comment