CSC367 NET Centric Computing

NET Centric ComputingUnit 315 min read

Controllers, Views, Razor Syntax & MVC Workflow in ASP.NET Core

Unit 3 of NET Centric Computing explores ASP.NET Core MVC's three-tier architecture, focusing on Controllers (request handling), Views (dynamic HTML generation), and Razor Syntax (C embedded in HTML). It covers action methods, view rendering, tag helpers, and real-world scenarios like eSewa's dynamic form generation or

TAKEAWAYS:

  • Controllers act as middleware between HTTP requests and business logic, returning ActionResults (View, JSON, Redirect, etc.).
  • Views use Razor syntax (@Model, @foreach, @Html.TagHelpers) to dynamically generate HTML from C# models.
  • Tag Helpers (e.g., <form asp-controller="Home" asp-action="Login">) replace HTML helpers for cleaner markup.
  • The MVC workflow follows: Request → Controller → Model → View → Response, with Razor parsing server-side before sending HTML.
  • Partial Views and View Components enable reusable UI components (e.g., headers, footers).
  • Layouts (e.g., _Layout.cshtml) standardize page structure across views.

1. Controllers: The Traffic Directors of ASP.NET Core MVC

Controllers are C# classes that handle HTTP requests, process data, and return responses. They sit between the client (browser/app) and the model (data/logic).

How Controllers Work

  1. Route Binding: ASP.NET Core maps incoming URLs to controller actions using attributes ([Route], [HttpGet], [HttpPost]).
  2. Action Methods: Each method handles a specific HTTP verb (GET, POST, PUT, DELETE).
  3. Return Types: Actions return ActionResult objects (e.g., View(), Json(), Redirect()).
HTTP Request (GET /Home/Index)Router matchesController: Home, ActiController (HomeController.cs)Action Method:public IActionResult IReturn View() or Json()Rendered HTML/JSON→ Sent to Client
Step-by-step MVC request handling in ASP.NET Core

Example: A Simple HomeController

[Route("Home")]
public class HomeController : Controller
{
    // GET: /Home/Index
    [HttpGet]
    public IActionResult Index()
    {
        var message = "Welcome to ASP.NET Core MVC!";
        return View(message); // Renders Index.cshtml with the model
    }

    // POST: /Home/Login
    [HttpPost]
    public IActionResult Login(string username, string password)
    {
        if (ValidateUser(username, password))
            return Redirect("/Dashboard");
        return View("LoginError"); // Renders a different view
    }
}

Key Attributes

Attribute Purpose
[Route("Home")] Base route for the controller (e.g., /Home/Index).
[HttpGet] Restricts action to GET requests.
[HttpPost] Restricts action to POST requests (e.g., form submissions).
[FromBody] Binds request body to method parameters (used in APIs).
[FromQuery] Binds query string parameters (e.g., /Home/Search?q=ASP.NET).


2. Views: Dynamic HTML Generation with Razor

Views are .cshtml files that combine HTML with Razor syntax to generate dynamic content. They receive data from controllers via ViewBag, ViewData, or @Model.

Model binding (e.g., 'Welcome to ASP.NET Core MVC!')@model stringConditional rendering (Admin Panel link)@if (User.IsInRole("Admin"))Loop through collections (e.g., product list)@foreach (var item in Model.Items)Razor View File (Index.cshtml)
Hierarchy of Razor syntax elements in a view file

Razor Syntax Basics

Syntax Example Output
Inline Code @DateTime.Now 12:34 PM, June 5, 2024
Model Access @Model.Name "John Doe" (from model)
Loops @foreach(var item in Model.Items) Renders each item in a list.
Conditional @if(Model.IsAdmin) { ... } Shows content only for admins.
HTML Helpers @Html.ActionLink("Home", "Index") <a href="/Home/Index">Home</a>

Example: Index.cshtml (View)

@model string  <!-- Declares the model type -->

<h1>@Model</h1>  <!-- Displays the string passed from controller -->

@if (User.IsInRole("Admin"))
{
    <p>Admin Panel: <a href="/Admin">Go</a></p>
}

Partial Views

Reusable UI components (e.g., headers, footers) stored in /Views/Shared/. Example: _Header.cshtml

<header>
    <h1>@ViewData["SiteName"]</h1>
    <nav>
        @Html.ActionLink("Home", "Index", "Home")
    </nav>
</header>

Usage in a View:

@await Html.PartialAsync("_Header", new { SiteName = "MyApp" })
0255075100_Layout.cshtml100_Header.cshtml30_Footer.cshtml30Product.cshtml40
Reusability impact: Layout (100% shared), Partial Views (30-40% shared across pages)


3. Tag Helpers: Simplifying HTML with C#

Tag Helpers replace HTML helpers (e.g., @Html.TextBox()) with cleaner, HTML-like syntax. They run at compile time.

classDiagram
    class FormTagHelper {
        +asp-controller: string
        +asp-action: string
        +method: string
    }
    class InputTagHelper {
        +asp-for: string
        +class: string
    }
    class LabelTagHelper {
        +asp-for: string
    }
    FormTagHelper --> InputTagHelper : contains
    FormTagHelper --> LabelTagHelper : contains
    note for FormTagHelper "Generates <form> with action=/Home/Login"
    note for InputTagHelper "Generates <input name='User.Name'>"
Tag Helper class relationships in ASP.NET Core

Common Tag Helpers

Tag Helper Example Output
<form> <form asp-controller="Home" asp-action="Login"> <form action="/Home/Login" method="post">
<input> <input asp-for="User.Name" /> <input name="User.Name" type="text">
<label> <label asp-for="User.Email"> <label for="User.Email">Email</label>
<select> <select asp-items="Model.Categories"> <select><option>Cat1</option></select>
<a> (ActionLink) <a asp-action="Details" asp-route-id="@item.Id"> <a href="/Home/Details/123">Details</a>

Example: Login Form with Tag Helpers

<form asp-controller="Account" asp-action="Login" method="post">
    <div class="form-group">
        <label asp-for="UserName"></label>
        <input asp-for="UserName" class="form-control" />
        <span asp-validation-for="UserName" class="text-danger"></span>
    </div>
    <button type="submit" class="btn btn-primary">Login</button>
</form>


4. The MVC Workflow: Request to Response

sequenceDiagram
    participant Client
    participant Router
    participant Controller
    participant Model
    participant View
    participant Response

    Client->>Router: GET /Home/Index
    Router->>Controller: Invoke HomeController.Index()
    Controller->>Model: Fetch data (e.g., DB query)
    Model-->>Controller: Return Product[] products
    Controller->>View: Render Index.cshtml with products
    View-->>Controller: Return ViewResult
    Controller-->>Response: Send HTML to Client
    Response->>Client: Display page

Real-World Example: Daraz Product Listing

  1. Request: User visits /Products/Electronics.
  2. Controller: ProductsController.GetElectronics() fetches data from a database.
  3. View: Electronics.cshtml uses @foreach to loop through products and @Html.DisplayFor() to show prices.
  4. Response: Dynamic HTML page with product cards is sent to the browser.
GET /Products?category=electronicsPOST /Cart/AddClient RequestFetch from ProductServiceApply business logicController Processing_Layout.cshtml (shared)ProductItem.cshtml (partial)View RenderingMVC Request Flow
Daraz-like e-commerce MVC structure


5. Layouts and Partial Views: Reusability

Layouts (_Layout.cshtml)

  • Define shared structure (headers, footers, navigation).
  • Views inherit from layouts using @{ Layout = "~/Views/Shared/_Layout.cshtml"; }.

Example Layout:

<!DOCTYPE html>
<html>
<head>
    <title>@ViewData["Title"] - MyApp</title>
</head>
<body>
    @RenderBody()  <!-- Renders the main content of the view -->
    @RenderSection("Scripts", required: false)  <!-- Optional scripts -->
</body>
</html>

View Sections

Allow views to override parts of the layout. Example: Index.cshtml

@{
    Layout = "_Layout";
    ViewData["Title"] = "Home Page";
}
<h1>Welcome</h1>
@section Scripts {
    <script src="~/js/home.js"></script>
}


6. Common Action Result Types

Result Type Example Use Case
View() return View(); Renders a view with default model.
View(model) return View(products); Renders a view with a model.
PartialView() return PartialView("_Header"); Returns a partial view fragment.
Json() return Json(new { Success = true }); Returns JSON for APIs.
Redirect() return Redirect("/Home"); Redirects to another URL.
RedirectToAction() return RedirectToAction("Details", "Product"); Redirects to another action.

Example: API Controller (JSON Responses)

[Route("api/[controller]")]
public class ProductsController : ControllerBase
{
    [HttpGet("{id}")]
    public IActionResult Get(int id)
    {
        var product = _db.Products.Find(id);
        if (product == null) return NotFound();
        return Ok(product); // Returns JSON with HTTP 200
    }

    [HttpPost]
    public IActionResult Create([FromBody] Product product)
    {
        _db.Products.Add(product);
        _db.SaveChanges();
        return CreatedAtAction(nameof(Get), new { id = product.Id }, product);
    }
}


In the Real World

  1. eSewa (Nepal)

    • Idea Used: Controllers + Razor Views
    • How: When you submit a bill payment form, eSewa’s backend uses a PaymentController to process the request. The ConfirmPayment.cshtml view dynamically generates a confirmation page with Razor, showing your transaction details (e.g., @Model.Amount, @Model.ReceiptNumber).
  2. Daraz (Nepal)

    • Idea Used: Tag Helpers + Partial Views
    • How: Product listing pages use <div asp-items="Model.Products"> to loop through items. The "Add to Cart" button is a partial view (_AddToCart.cshtml) reused across all product pages.
  3. Khalti (Nepal)

    • Idea Used: Action Results (JSON + Redirect)
    • How: After you initiate a payment, Khalti’s API returns Json(new { Status = "Pending", Url = "/payment/confirm" }). If successful, it redirects to /payment/success using RedirectToAction().
  4. Ncell’s MyNcell App (Nepal)

    • Idea Used: Layouts + View Sections
    • How: The app’s dashboard uses _Layout.cshtml for the navigation bar and footer. Individual pages (e.g., BillPayment.cshtml) inject their content into @RenderBody() while keeping the same header/footer.
  5. Google Search (Global)

    • Idea Used: Controllers + Dynamic Views
    • How: When you search for "ASP.NET Core," Google’s backend routes the request to a SearchController, which fetches results and renders them in SearchResults.cshtml using Razor loops (@foreach(var result in Model.Results)).

Worked Example: Kathmandu Traffic Route Optimization

Scenario: Imagine a traffic management system for Kathmandu where sensors send data to a backend. The system uses ASP.NET Core MVC to display real-time traffic maps.

  1. Controller:

    [Route("Traffic")]
    public class TrafficController : Controller
    {
        [HttpGet("Map")]
        public IActionResult Map()
        {
            var trafficData = _sensorService.GetLiveData();
            return View(trafficData); // Renders Map.cshtml
        }
    }
    
  2. View (Map.cshtml):

    @model List<TrafficSensorData>
    <div id="map" style="height: 500px;"></div>
    @foreach (var sensor in Model)
    {
        <script>
            // JavaScript to plot sensor data on a map
            plotTrafficPoint(@sensor.Latitude, @sensor.Longitude, @sensor.Status);
        </script>
    }
    
  3. Tag Helper for Filters:

    <select asp-for="Filter" asp-items="Model.AvailableFilters">
        <option value="">All</option>
    </select>
    

Real-World Tie-In:

  • The system could integrate with NTC’s traffic cameras (like those on ntc.gov.np) to fetch live data.
  • Partial Views could show alerts for congested routes (e.g., _CongestionAlert.cshtml).

Exam Tip

  1. Controller Questions:

    • Always show attributes ([Route], [HttpGet]) and return types (IActionResult).
    • For API controllers, use [Route("api/[controller]")] and return Json().
    • Common Pitfalls:
      • Forgetting [HttpPost] for form submissions (causes 405 errors).
      • Not specifying [FromBody] for JSON payloads in POST/PUT.
  2. Razor Syntax:

    • Memorize @model, @foreach, @if, and @Html.TagHelpers.
    • Exam Favorite: Write a view that loops through a list and uses @Html.DisplayFor().
    • Trick: @ViewData vs. @ViewBag:
      • @ViewData is strongly typed (requires casting).
      • @ViewBag is dynamic (no casting needed).
  3. Action Results:

    • JSON: Use Json() for APIs.
    • Redirects: Use RedirectToAction() for internal links.
    • Partial Views: Use PartialView() for reusable components.
  4. Layouts and Partial Views:

    • Always declare @{ Layout = "_Layout"; } in views.
    • Use @RenderSection() for optional scripts/styles.
  5. Real-World Scenarios:

    • eSewa/Khalti: Focus on controllers handling payments and Razor views for receipts.
    • Daraz: Emphasize tag helpers for product listings and partial views for carts.
    • Ncell: Highlight layouts for consistent UI and JSON responses for APIs.

Final Pro Tip:

  • Draw the MVC workflow in exams if asked about "how ASP.NET Core processes a request."
  • Use Mermaid diagrams in answers to show controller actions or Razor loops (examiners love visuals!).
  • Practice: Build a mini-project (e.g., a "Library Management" app) with:
    • A BooksController with CRUD actions.
    • Razor views for listing/editing books.
    • A layout with a navigation bar.

In the real world

  • Daraz (Nepal): Uses Controllers to handle /Products/Electronics requests, fetching data from its database via Models, then rendering dynamic product cards in Views with Razor loops (@foreach).
  • eSewa: Employs Tag Helpers in its payment forms (e.g., <input asp-for="UserPhone" />) to bind user input to C# model properties, ensuring validation and security.
  • Ncell App: Leverages Partial Views for reusable UI components like headers/footers across all pages, reducing code duplication and improving maintainability.

Based on the TU BSc CSIT syllabus for NET Centric Computing (CSC367), unit 3.

Discussion

Loading…