Views in ASP.NET MVC Application explained
In the Model-View-Controller (MVC) pattern, the view handles
the application's data presentation and user interaction. A view is an HTML
template with embedded Razor markup. Razor markup is code that interacts with HTML markup to
produce a webpage that's sent to the client.
In ASP.NET MVC, views are .cshtml files that
use the C# programming language in Razor markup. Usually, view files are grouped
into folders named for each of the application's controllers. The folders are stored in a Views folder
at the root of the application as shown:
The Home controller is represented by a Home folder
inside the Views folder.
The Home folder
contains the views for the About, Contact, and Index (homepage)
webpages. When a user requests one of these three webpages, controller actions
in the Home controller determine which of the three views is
used to build and return a webpage to the user as shown below.
You can learn to
create a controller and its action methods’ views can be found here
Layouts in MVC
Use layouts to provide consistent webpage sections and reduce
code repetition. Layouts often contain the header, navigation and menu
elements, and the footer. The header and footer usually contain boilerplate
markup for many metadata elements and links to script and style assets. Layouts
help you avoid this boilerplate markup in your views.
The layout view is stored
in Shared Folder as can be seen below
The boilerplate of Layout makeup is as shown below;
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width,
initial-scale=1.0">
<title>@ViewBag.Title - Database first
Applicationroach</title>
@Styles.Render("~/Content/css")
@Scripts.Render("~/bundles/modernizr")
</head>
<body>
<div class="navbar
navbar-inverse navbar-fixed-top">
<div class="container">
<div class="navbar-header">
<button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".navbar-collapse">
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
@Html.ActionLink("Csharpnaija
Entity Framework", "Index", "Home", new {
area = "" }, new {
@class = "navbar-brand" })
</div>
<div class="navbar-collapse
collapse">
<ul class="nav
navbar-nav">
<li>@Html.ActionLink("Home", "Index", "Home")</li>
<li>@Html.ActionLink("Employees", "Index", "employees")</li>
<li>@Html.ActionLink("Departments", "Index", "departments")</li>
<li>@Html.ActionLink("About", "About", "Home")</li>
<li>@Html.ActionLink("Contact", "Contact", "Home")</li>
</ul>
@Html.Partial("_LoginPartial")
</div>
</div>
</div>
<div class="container
body-content">
@RenderBody()
<hr />
<footer>
<p>© @DateTime.Now.Year - Database
first Applicationroach</p>
</footer>
</div>
@Scripts.Render("~/bundles/jquery")
@Scripts.Render("~/bundles/bootstrap")
@RenderSection("scripts",
required: false)
</body>
</html>
Partial Views in MVC
Partial views reduce code duplication by managing reusable parts
of views. For example, a partial view is useful for an author biography on a
blog website that appears in several views. An author biography is ordinary
view content and doesn't require code to execute in order to produce the
content for the webpage. Author biography content is available to the view by
model binding alone, so using a partial view for this type of content is ideal.
LoginPartial is an example of a partial view
@using
Microsoft.AspNet.Identity
@if
(Request.IsAuthenticated)
{
using
(Html.BeginForm("LogOff", "Account",
FormMethod.Post, new { id = "logoutForm", @class = "navbar-right" }))
{
@Html.AntiForgeryToken()
<ul class="nav
navbar-nav navbar-right">
<li>
@Html.ActionLink("Hello " +
User.Identity.GetUserName() + "!", "Index", "Manage",
routeValues: null, htmlAttributes: new { title = "Manage" })
</li>
<li><a href="javascript:document.getElementById('logoutForm').submit()">Log
off</a></li>
</ul>
}
}
else
{
<ul class="nav
navbar-nav navbar-right">
<li>@Html.ActionLink("Register", "Register", "Account",
routeValues: null, htmlAttributes: new { id = "registerLink" })</li>
<li>@Html.ActionLink("Log
in", "Login", "Account",
routeValues: null, htmlAttributes: new { id = "loginLink" })</li>
</ul>
}
Importance of using views
Views help to establish separation of
concerns within an MVC application
by separating the user interface markup from other parts of the application.
Following SoC (Separation of Concern) design makes your application modular,
which provides several benefits:
·
The application is
easier to maintain because it's better organized. Views are generally grouped
by application feature. This makes it easier to find related views when working
on a feature.
·
The parts of the application
are loosely coupled. You can build and update the application's views
separately from the business logic and data access components. You can modify
the views of the application without necessarily having to update other parts
of the application.
·
It's easier to test
the user interface parts of the application because the views are separate
units.
·
Due to better
organization, it's less likely that you'll accidentally repeat sections of the
user interface.
Creating a view for a given Action method
Views that are specific to a controller are created in the Views/[ControllerName] folder.
Views that are shared among controllers are placed in the Views/Shared folder.
To create a view, add a new file and give it the same name as its associated
controller action with the .cshtml file extension.
The About view in Home Controller
@{
ViewBag.Title = "About";
}
<h2>@ViewBag.Title.</h2>
<h3>@ViewBag.Message</h3>
<p>Use
this area to provide additional information.</p>
Razor markup starts with the @ symbol. Run C#
statements by placing C# code within Razor code
blocks set off by curly braces ({ ...
}). For example, see the assignment of "About" to ViewBag.Title
shown above. You can
display values within HTML by simply referencing the value with the @ symbol.
See the contents of the <h2> and <h3> elements
above.
The view content shown above is only part of the entire webpage
that's rendered to the user. The rest of the page's layout and other common
aspects of the view are specified in other view files.
How Views are specified in controllers
Views are typically returned from actions as a ViewResult, which is a type of ActionResult. Your action method can create and return a ViewResult directly,
but that isn't commonly done. Since most controllers inherit from Controller, you simply use the View helper method to
return the ViewResult:
HomeController.cs
public ActionResult About()
{
ViewBag.Message = "Csharp naija Blog.";
return
View();
}
When this action returns, the About.cshtml view
shown in the last section is rendered as the following webpage:
The View helper method has several overloads. You can
optionally specify:
An explicit view to
return: return View("Index");
A model to
pass to the view: return View(employee);
Both a view and a
model: return View("Get",
employee);
How Views are discovered in ASP.NET MVC
When an action returns a view, a process called view
discovery takes place. This process determines which view file is used
based on the view name.
The default behavior of the View method (return
View();) is to return a view with the same name as the action method from which
it's called.
For example, the About ActionResult method
name of the controller is used to search for a view file named About.cshtml.
First, the runtime looks in the Views/[ControllerName] folder
for the view e.g Views/Home. If it doesn't find a matching view there, it
searches the Shared folder for the view.
It doesn't matter if you implicitly return the ViewResult with return
View(); or explicitly pass the view name to the View method
with return View("<ViewName>");. In both cases, view discovery
searches for a matching view file in this order:
1.
Views/[ControllerName]/[ViewName].cshtml
2.
Views/Shared/[ViewName].cshtml
A view file path can be provided instead of a view name. If
using an absolute path starting at the application root (optionally starting
with "/" or "~/"), the .cshtml extension
must be specified:
return View("Views/Home/About.cshtml");
You can also use a relative path to specify views in different
directories without the .cshtml extension. Inside the HomeController,
you can return the Index view of your Manage views
with a relative path:
return View("../Manage/Index");
Similarly, you can indicate the current controller-specific
directory with the "./" prefix:
return View("./About");
You can customize the default convention for how views are
located within the application by using a custom IViewLocationExpander.
Follow the best practice of organizing the file structure for
your views to reflect the relationships among controllers, actions, and views
for maintainability and clarity.
Passing data to views
Pass data to views using several approaches:
Strongly typed data are pass using viewmodel but with weakly
typed data we either us ViewData (ViewDataAttribute) or ViewBag.
Strongly typed data (viewmodel) in Views
The most robust approach is to specify a model type in the view. This model is commonly referred
to as a viewmodel. You pass an instance of the viewmodel type to
the view from the action.
Using a viewmodel to pass data to a view allows the view to take
advantage of strong type checking. Strong typing (or strongly
typed) means that every variable and constant has an explicitly defined
type (for example, string, int, or DateTime). The validity of
types used in a view is checked at compile time.
Visual Studio list strongly typed class members using a feature
called IntelliSense. When you want to see the properties of a viewmodel,
type the variable name for the viewmodel followed by a period (.). This helps
you write code faster with fewer errors.
Specify a model using the @model directive. Use the
model with @Model:
CSHTML Code
@model DatabaseFirstApproach.Models.ContactViewModel
@{
ViewBag.Title = "Contact";
}
<h2>@ViewBag.Title.</h2>
<h3>@ViewBag.Message</h3>
<h2>Contact</h2>
<address>
@Model.Address <br />
@Model.State <br />
@Model.City <br />
@Model.Street<br />
<abbr title="Phone">P:</abbr>
@Model.phoneNumber
</address>
<address>
<strong>Support:</strong>
<a href="mailto:Support@example.com">Support@example.com</a><br />
<strong>Marketing:</strong> <a href="mailto:Marketing@example.com">Marketing@example.com</a>
</address>
To provide the model to the view, the controller passes it as a
parameter:
Controller Code
public ActionResult Contact()
{
ViewBag.Message = "Your contact page.";
var viewModel = new ContactViewModel()
{
Address = "Durumi II Abuja",
phoneNumber = "08032299383",
State = "FCT",
City = "Abuja",
Street = "No 23 behind Durumi II Primary School"
};
return View();
}
There are no restrictions on the model types that you can
provide to a view. We recommend using Plain Old CLR Object (POCO) viewmodels
with little or no behavior (methods) defined. Usually, viewmodel classes are
either stored in the Models folder or a separate ViewModels folder
at the root of the application.
The ContactViewModel viewmodel used in the example above is a
POCO viewmodel stored in a file named ContactViewModel.cs:
Model Code
namespace DatabaseFirstApproach.Models
{
public class ContactViewModel
{
public string Address
{ get; set; }
public string Street
{ get; set; }
public string
phoneNumber { get; set; }
public string City { get; set; }
public string State {
get; set; }
}
}
Nothing prevents you from using the same classes for both your
viewmodel types and your business model types. However, using separate models
allows your views to vary independently from the business logic and data access
parts of your application. Separation of models and viewmodels also offers
security benefits when models use model binding and validation for data sent to the application by the user.
Weakly typed data (ViewData, ViewData attribute, and ViewBag)
In addition to strongly typed views, views have access to
a weakly typed (also called loosely typed)
collection of data. Unlike strong types, weak types (or loose
types) means that you don't explicitly declare the type of data you're
using. You can use the collection of weakly typed data for passing small
amounts of data in and out of controllers and views.
This
collection can be referenced through either the ViewData or ViewBag properties
on controllers and views. The ViewData property is a dictionary of
weakly typed objects. The ViewBag property is a wrapper around ViewData that
provides dynamic properties for the underlying ViewData collection.
Note: Key lookups are case-insensitive for both ViewData and ViewBag.
ViewData and ViewBag are dynamically resolved at
runtime. Since they don't offer compile-time type checking, both are generally
more error-prone than using a viewmodel. For that reason, some developers
prefer to minimally or never use ViewData and ViewBag.
ViewData in MVC
ViewData is a ViewDataDictionary object accessed through string keys.
String data can be stored and used directly without the need for a cast, but
you must cast other ViewData object values to specific types when you
extract them. You can use ViewData to pass data from controllers to
views and within views, including partial views and layouts.
The following is an example that sets values for a greeting and
an address using ViewData in an action:
public ActionResult ViewDataContact()
{
ViewData["Message"] = "Your contact page.";
ViewData["Contact"] = new ContactViewModel()
{
Address = "Durumi II Abuja",
phoneNumber = "08032299383",
State = "FCT",
City = "Abuja",
Street = "No 23 behind Durumi II Primary School"
};
return View();
}
Work with the data in a view:
CSHTML
@{
ViewBag.Title = "Contact";
var contact = ViewData["Contact"] as
DatabaseFirstApproach.Models.ContactViewModel;
}
<h2>@ViewBag.Title.</h2>
<h3>@ViewBag.Message</h3>
<h2>Contact</h2>
<address>
<b>Address:</b> @contact.Address <br />
<b>State:</b> @contact.State <br />
<b>City:</b> @contact.City <br />
<b>Street</b> @contact.Street<br />
<b><abbr title="Phone">P:</abbr></b>
@contact.phoneNumber
</address>
<address>
<strong>Support:</strong><a href="mailto:Support@example.com">Support@example.com</a><br />
<strong>Marketing:</strong> <a href="mailto:Marketing@example.com">Marketing@example.com</a>
</address>
ViewData attribute on controller properties
We can also use the ViewDataAttribute
of ViewDataDictionary. Properties on controllers or Razor Page models marked
with the [ViewData] attribute have their values stored and loaded
from the dictionary.
ViewBag in MVC
ViewBag is a DynamicViewData object
that provides dynamic access to the objects stored in ViewData. ViewBag can
be more convenient to work with, since it doesn't require casting. The
following example shows how to use ViewBag with the same result as
using ViewData above:
Controller Code
public ActionResult ViewDataContact()
{
ViewBag.Message = "Your contact page.";
ViewBag.Contact = new ContactViewModel()
{
Address = "Durumi II Abuja",
phoneNumber = "08032299383",
State = "FCT",
City = "Abuja",
Street = "No 23 behind Durumi II Primary School"
};
return View();
}
CSHTML
@{
ViewBag.Title = "Contact";
var contact = ViewBag.Contact;
}
<h2>@ViewBag.Title.</h2>
<h3>@ViewBag.Message</h3>
<h2>Contact</h2>
<address>
<b>Address:</b> @contact.Address <br />
<b>State:</b> @contact.State <br />
<b>City:</b> @contact.City <br />
<b>Street</b> @contact.Street<br />
<b><abbr title="Phone">P:</abbr></b>
@contact.phoneNumber
</address>
<address>
<strong>Support:</strong>
<a href="mailto:Support@example.com">Support@example.com</a><br />
<strong>Marketing:</strong> <a href="mailto:Marketing@example.com">Marketing@example.com</a>
</address>
Using ViewData and ViewBag at the same controller action
Since ViewData and ViewBag refer to the same
underlying ViewData collection, you can use both ViewData and ViewBag and
mix and match between them when reading and writing values.
When to use ViewData or ViewBag
Both ViewData and ViewBag are equally valid approaches
for passing small amounts of data among controllers and views. The choice of
which one to use is based on preference. You can mix and match ViewData and ViewBag objects,
however, the code is easier to read and maintain with one approach used
consistently. Both approaches are dynamically resolved at runtime and thus
prone to causing runtime errors. Some development teams avoid them.
Dynamic views
Views that don't declare a model type using @model but
that have a model instance passed to them (for example, return View(contact);)
can reference the instance's properties dynamically:
CSHTML
<address>
@Model.Address<br>
@Model.City, @Model.State @Model.Street<br>
<abbr title="Phone">P:</abbr>
@Model.PhoneNumber
</address>
This feature offers flexibility but doesn't offer compilation
protection or IntelliSense. If the property doesn't exist, webpage generation
fails at runtime.
Comments
Post a Comment