Skip to main content

.NET Views

Introduction

Views are a fundamental component in ASP.NET web applications that handle the presentation layer of your application. They are responsible for rendering HTML to the client browser based on the data provided by controllers or page models.

In the MVC (Model-View-Controller) and Razor Pages architectures of ASP.NET Core, views are primarily created using Razor, which is a markup syntax that combines HTML with C# code. Understanding how views work is essential for creating dynamic and interactive web applications with .NET.

In this guide, we'll explore:

  • What views are and how they fit into the .NET web architecture
  • How to create and structure views
  • How to pass data to views
  • View components and partial views
  • Best practices for working with views

What Are Views?

Views in .NET are files that contain HTML markup mixed with C# code. They are responsible for:

  1. Rendering HTML content to be displayed in a web browser
  2. Displaying data passed from controllers or page models
  3. Providing a separation between presentation logic and business logic

In ASP.NET Core MVC, views are typically stored in the /Views folder, organized by controller, while in Razor Pages, they are stored in the /Pages folder.

Creating Your First View

Let's create a simple view to understand the basics.

Basic View Structure (MVC)

In an ASP.NET Core MVC application, a basic view file might look like this:

csharp
@{
ViewData["Title"] = "Welcome Page";
}

<h1>Welcome to My Application</h1>

<p>Hello, @ViewData["UserName"]!</p>

<div class="row">
<div class="col-md-6">
<h2>Getting Started</h2>
<p>Learn how to build ASP.NET Core MVC apps:</p>
<ul>
<li><a href="https://docs.microsoft.com/aspnet/core">ASP.NET Core Documentation</a></li>
<li><a href="https://docs.microsoft.com/aspnet/core/mvc/overview">ASP.NET Core MVC</a></li>
</ul>
</div>
</div>

Razor Pages View Structure

In Razor Pages, a basic page might look like this:

csharp
@page
@model IndexModel
@{
ViewData["Title"] = "Home page";
}

<div class="text-center">
<h1 class="display-4">Welcome</h1>
<p>Hello, @Model.UserName!</p>
<p>Learn about <a href="https://docs.microsoft.com/aspnet/core">building Web apps with ASP.NET Core</a>.</p>
</div>

Key Components of Razor Views

Razor Syntax

Razor uses the @ symbol to transition from HTML to C#. Here are some examples:

csharp
<!-- Single statement -->
<p>The current date is @DateTime.Now</p>

<!-- Code block -->
@{
var message = "Hello, World!";
var number = 42;
}

<p>@message The answer is @number</p>

<!-- Conditional statements -->
@if (User.IsInRole("Admin"))
{
<div class="admin-panel">You are an admin!</div>
}
else
{
<div>Welcome, user!</div>
}

<!-- Loops -->
<ul>
@foreach (var item in Model.Items)
{
<li>@item.Name: @item.Description</li>
}
</ul>

Layout Pages

Layout pages in .NET provide a consistent template for your application. They typically contain the common elements like headers, footers, and navigation menus.

A basic layout file (_Layout.cshtml) might look like:

csharp
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>@ViewData["Title"] - My Application</title>
<link rel="stylesheet" href="~/css/site.css" />
<link rel="stylesheet" href="~/lib/bootstrap/dist/css/bootstrap.min.css" />
</head>
<body>
<header>
<nav class="navbar navbar-expand-sm navbar-toggleable-sm navbar-light bg-white border-bottom box-shadow mb-3">
<!-- Navigation content -->
</nav>
</header>

<div class="container">
<main role="main" class="pb-3">
@RenderBody()
</main>
</div>

<footer class="border-top footer text-muted">
<div class="container">
&copy; 2023 - My Application - <a asp-area="" asp-page="/Privacy">Privacy</a>
</div>
</footer>

<script src="~/lib/jquery/dist/jquery.min.js"></script>
<script src="~/lib/bootstrap/dist/js/bootstrap.bundle.min.js"></script>
<script src="~/js/site.js" asp-append-version="true"></script>

@RenderSection("Scripts", required: false)
</body>
</html>

Passing Data to Views

Using Models

The cleanest way to pass data to views is through strongly-typed models:

csharp
// In your controller
public IActionResult Index()
{
var user = new UserViewModel
{
Name = "John Doe",
Email = "[email protected]",
JoinDate = DateTime.Now.AddYears(-1)
};

return View(user);
}

Then in your view:

csharp
@model UserViewModel

<h1>User Profile</h1>
<div class="user-card">
<h2>@Model.Name</h2>
<p>Email: @Model.Email</p>
<p>Member since: @Model.JoinDate.ToString("MMMM yyyy")</p>
</div>

Using ViewData and ViewBag

ViewData and ViewBag provide ways to pass data from controllers to views:

csharp
// In your controller
public IActionResult About()
{
ViewData["Title"] = "About Page";
ViewData["Message"] = "Your application description page.";

ViewBag.CurrentUser = "John";

return View();
}

Then in your view:

csharp
<h1>@ViewData["Title"]</h1>
<p>@ViewData["Message"]</p>
<p>Welcome, @ViewBag.CurrentUser!</p>

Partial Views

Partial views allow you to split your UI into reusable components. They're great for components that appear on multiple pages like navigation menus, sidebars, or product cards.

Creating a Partial View

Create a file named _ProductCard.cshtml (the underscore prefix is a convention for partial views):

csharp
@model ProductViewModel

<div class="product-card">
<img src="@Model.ImageUrl" alt="@Model.Name" />
<h3>@Model.Name</h3>
<p>@Model.Description</p>
<p class="price">$@Model.Price.ToString("0.00")</p>
<button class="btn btn-primary">Add to Cart</button>
</div>

Using a Partial View

There are multiple ways to render a partial view:

csharp
<!-- Method 1: Using partial tag helper -->
<partial name="_ProductCard" model="@product" />

<!-- Method 2: Using HTML helper -->
@await Html.PartialAsync("_ProductCard", product)

<!-- Method 3: In a loop -->
@foreach (var product in Model.Products)
{
<partial name="_ProductCard" model="@product" />
}

View Components

View components are similar to partial views but have more functionality. They're perfect for reusable parts of the UI that require some processing or business logic.

Creating a View Component

  1. Create the view component class:
csharp
using Microsoft.AspNetCore.Mvc;
using System.Threading.Tasks;

public class ShoppingCartSummaryViewComponent : ViewComponent
{
private readonly IShoppingCartService _cartService;

public ShoppingCartSummaryViewComponent(IShoppingCartService cartService)
{
_cartService = cartService;
}

public async Task<IViewComponentResult> InvokeAsync()
{
var items = await _cartService.GetCartItemsAsync(HttpContext.User.Identity.Name);
return View(items);
}
}
  1. Create the view component's view in Views/Shared/Components/ShoppingCartSummary/Default.cshtml:
csharp
@model List<CartItemViewModel>

<div class="cart-summary">
<h3>Your Cart (@Model.Count)</h3>

@if (Model.Any())
{
<ul>
@foreach (var item in Model)
{
<li>@item.ProductName (@item.Quantity) - $@item.TotalPrice.ToString("0.00")</li>
}
</ul>
<p>Total: $@Model.Sum(item => item.TotalPrice).ToString("0.00")</p>
<a href="/Cart" class="btn btn-primary">View Cart</a>
}
else
{
<p>Your cart is empty.</p>
}
</div>
  1. Using the view component:
csharp
<!-- Method 1 -->
@await Component.InvokeAsync("ShoppingCartSummary")

<!-- Method 2 with Tag Helper -->
<vc:shopping-cart-summary></vc:shopping-cart-summary>

Tag Helpers

Tag Helpers enable server-side code to help create and render HTML elements in Razor files. They provide an HTML-like syntax for working with server-side code.

Common Tag Helpers

csharp
<!-- Link to a controller action -->
<a asp-controller="Home" asp-action="Index">Home</a>

<!-- Form posting to a specific action -->
<form asp-controller="Account" asp-action="Login" method="post">
<!-- Input with validation -->
<input asp-for="Email" class="form-control" />
<span asp-validation-for="Email" class="text-danger"></span>

<!-- Submit button -->
<button type="submit" class="btn btn-primary">Login</button>
</form>

<!-- Image with version tag for cache busting -->
<img src="~/images/logo.png" asp-append-version="true" />

Real-World Example

Let's build a simple product listing page that demonstrates several of the concepts we've discussed.

Model

csharp
// Models/Product.cs
public class Product
{
public int Id { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public decimal Price { get; set; }
public string ImageUrl { get; set; }
public bool IsInStock { get; set; }
}

// ViewModels/ProductListViewModel.cs
public class ProductListViewModel
{
public List<Product> Products { get; set; }
public string CategoryName { get; set; }
public int TotalProducts { get; set; }
}

Controller

csharp
// Controllers/ProductController.cs
public class ProductController : Controller
{
private readonly IProductService _productService;

public ProductController(IProductService productService)
{
_productService = productService;
}

public async Task<IActionResult> Index(string category = "All Products")
{
var products = await _productService.GetProductsByCategoryAsync(category);

var viewModel = new ProductListViewModel
{
Products = products,
CategoryName = category,
TotalProducts = products.Count
};

return View(viewModel);
}
}

View

csharp
@model ProductListViewModel

@{
ViewData["Title"] = "Products - " + Model.CategoryName;
}

<div class="container">
<h1>@Model.CategoryName</h1>
<p>Showing @Model.TotalProducts products</p>

<div class="row">
@foreach (var product in Model.Products)
{
<div class="col-md-4 mb-4">
<partial name="_ProductCard" model="@product" />
</div>
}
</div>

@if (!Model.Products.Any())
{
<div class="alert alert-info">
No products found in this category.
</div>
}
</div>

@section Scripts {
<script src="~/js/product-page.js"></script>
}

Partial View

csharp
@model Product

<div class="card product-card">
<img src="@(string.IsNullOrEmpty(Model.ImageUrl) ? "/images/no-image.jpg" : Model.ImageUrl)"
class="card-img-top" alt="@Model.Name">
<div class="card-body">
<h5 class="card-title">@Model.Name</h5>
<p class="card-text">@Model.Description</p>
<p class="price">$@Model.Price.ToString("0.00")</p>

@if (Model.IsInStock)
{
<a asp-controller="Cart" asp-action="Add" asp-route-id="@Model.Id"
class="btn btn-primary">Add to Cart</a>
}
else
{
<button class="btn btn-secondary" disabled>Out of Stock</button>
}
</div>
</div>

Best Practices for Working with Views

  1. Keep Views Simple - Views should focus on display logic, not business logic. If your view requires complex logic, consider moving that code to a controller or a view component.

  2. Use Strongly-Typed Models - Use strongly-typed models instead of ViewData or ViewBag when possible for better compile-time checking.

  3. Use Partial Views for Reusable Content - Extract repeated UI elements into partial views.

  4. Use View Components for Complex UI Elements - If a UI element requires significant logic, use a view component instead of a partial view.

  5. Use Tag Helpers - They provide a cleaner, more HTML-like syntax compared to HTML helpers.

  6. Implement Layouts Properly - Use layout pages for consistent UI elements across your application.

  7. Use Client-Side Libraries Responsibly - Make use of npm or LibMan to manage your client-side libraries.

  8. Optimize for Performance - Minimize JS and CSS files, and use bundling and minification.

Summary

Views are a crucial part of ASP.NET Core applications, handling how data is presented to users. In this article, we've covered:

  • The basics of creating and using views
  • How to pass data to views using models, ViewData, and ViewBag
  • Working with layouts to maintain consistent design
  • Creating reusable UI components with partial views and view components
  • Using tag helpers for cleaner HTML generation
  • Best practices for organizing and implementing views

By effectively utilizing views and following the patterns we've discussed, you can create well-structured, maintainable web applications with clean separation between business logic and presentation.

Additional Resources

Exercises

  1. Create a basic MVC application with a home page that displays a list of your favorite books or movies.
  2. Implement a partial view for displaying a contact form that can be reused across multiple pages.
  3. Create a view component that displays the current weather based on the user's location.
  4. Build a product catalog page with filtering options using forms and tag helpers.
  5. Implement a master/detail view where clicking on an item in a list shows its details in another part of the page.


If you spot any mistakes on this website, please let me know at [email protected]. I’d greatly appreciate your feedback! :)