Unit 4: Backend Development Using ASP.NET Core

CSE253 — .Net Programming 10 min read

I. Orientation — ASP.NET Core as a Web Framework

ASP.NET Core is Microsoft’s open-source, cross-platform framework for building web applications and HTTP services. It processes requests through a configurable middleware pipeline and commonly uses the Model-View-Controller pattern to separate data, presentation, and request-handling responsibilities.

  • Cross-platform runtime: Applications run on Windows, Linux, and macOS using modern .NET.
  • Middleware pipeline: Each HTTP request passes through ordered components configured in Program.cs.
  • Dependency injection: Services are registered with builder.Services and supplied to constructors by the framework.
  • Convention and configuration: Routing, model binding, Razor conventions, and environment-specific settings reduce repetitive code.
  • Asynchronous execution: Controllers commonly return Task<IActionResult> and use await for database or network operations.
  • Security assumptions: HTTPS, authentication, authorization, anti-forgery protection, input validation, and secure cookie settings must be deliberately configured.
  • Application structure:
    • Controllers/: request-handling classes.
    • Models/: domain, input, and view data classes.
    • Views/: Razor templates, normally grouped by controller.
    • wwwroot/: public static files such as CSS and JavaScript.
    • Program.cs: service registration and request-pipeline configuration.

II. Application Processing — From HTTP Request to MVC Result

A. Building Web Applications using ASP.NET Core

An ASP.NET Core application is built by registering required services and arranging middleware in the order requests should encounter it.

  • Project configuration: WebApplication.CreateBuilder(args) creates a builder containing configuration, logging, and dependency-injection facilities.
  • MVC registration: AddControllersWithViews() registers controller, view, model-binding, and validation services.
  • Pipeline configuration: Routing identifies an endpoint, while authorization checks access before the endpoint executes.
  • Conventional route: {controller=Home}/{action=Index}/{id?} selects default controller and action values; id? means the parameter is optional.
CSHARP
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddControllersWithViews();

var app = builder.Build();
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseAuthorization();

app.MapControllerRoute(
    name: "default",
    pattern: "{controller=Home}/{action=Index}/{id?}");

app.Run();
  • Middleware order: UseStaticFiles() can serve files without invoking MVC, while UseAuthorization() must run after routing has selected an endpoint.

B. MVC Architecture and Model-View-Controller Communication

MVC divides an application into coordinated components so that business data, user interface, and request processing remain independently maintainable.

  1. Model: Represents application data, rules, or user input; for example, a Product may contain Id, Name, and Price.
  2. View: Uses Razor to transform model data into HTML; it should contain presentation logic rather than database operations.
  3. Controller: Receives the request, invokes services or model operations, and selects a response or view.
  • Communication flow: A request for /Products/Details/5 reaches ProductsController.Details(5), which loads product 5 and calls View(product).
  • Typed transfer: return View(product) makes the product the view’s Model.
  • Separation benefit: A controller can be unit-tested without rendering HTML, while the view can be changed without rewriting domain rules.

C. Handling Requests and Responses

ASP.NET Core converts an incoming HTTP request into an HttpRequest object and writes the selected result to an HttpResponse.

  • Request data: Request.Method, Request.Path, Request.Query, Request.Headers, Request.Cookies, and Request.Body expose HTTP input.
  • Response data: Status codes, headers, content type, cookies, and body represent the server’s outcome.
  • Common results:
    • View(model) returns rendered HTML, normally with status 200.
    • Json(data) returns JSON.
    • NotFound() returns status 404.
    • BadRequest() returns status 400.
    • RedirectToAction("Index") usually returns a 302 redirect.
  • Asynchronous handling: await repository.FindAsync(id) prevents a thread from being blocked while waiting for I/O.

D. Controllers and Actions

A controller is a class that groups related public action methods, each of which handles an endpoint and returns an action result.

  • Controller convention: ProductsController : Controller is normally stored in Controllers/ProductsController.cs.
  • Action selection: Attributes such as [HttpGet], [HttpPost], and [Route("products/{id:int}")] constrain eligible requests.
  • Result abstraction: IActionResult permits different outcomes, such as a view when data exists and NotFound() otherwise.
  • Dependency injection: A repository or database context is received through the controller constructor rather than instantiated inside an action.
CSHARP
[HttpGet]
public IActionResult Details(int id)
{
    var product = repository.Find(id);
    return product is null ? NotFound() : View(product);
}
  • Routing anchor: In /Products/Details/5, Products identifies the controller, Details the action, and 5 the id argument.

III. Razor Presentation — Views, Composition, and Temporary Data

A. Razor View Engine and Razor Syntax

The Razor view engine combines HTML with C# to generate server-side HTML files having the .cshtml extension.

  • Code marker: @ introduces C#; @Model.Name prints an encoded value, while @{ ... } creates a code block.
  • Strongly typed view: @model Product declares the expected model type; Model accesses its instance.
  • Control structures: @if, @for, @foreach, and @switch generate conditional or repeated markup.
  • Encoding: Razor HTML-encodes ordinary expressions, so text such as <script> is displayed rather than executed.
CSHTML
@model Product
<h2>@Model.Name</h2>
@if (Model.Price > 1000)
{
    <span>Premium</span>
}
  • Responsibility boundary: Formatting a price belongs in the view, but calculating a discount belongs in a model or service.

B. Layouts, Sections and View Start

Razor composition avoids repeated page structure by using layouts, optional sections, and shared view initialization.

  • Layout: _Layout.cshtml provides shared <html>, navigation, and footer markup; @RenderBody() marks where each view is inserted.
  • Sections: A view declares @section Scripts { ... }, and the layout renders it using @RenderSection("Scripts", required: false).
  • View start: _ViewStart.cshtml runs before views and commonly assigns Layout = "_Layout";.
  • View imports: _ViewImports.cshtml, though distinct from view start, commonly imports namespaces and enables Tag Helpers.
  • Scope: A _ViewStart.cshtml applies to views in its directory and descendant directories unless overridden.

C. Data Passing Techniques - ViewBag, ViewData and TempData

These mechanisms transfer small auxiliary values when a dedicated strongly typed view model would be unnecessary.

  1. ViewBag and ViewData:
    • ViewData: A dictionary accessed as ViewData["Title"]; values may require casting.
    • ViewBag: A dynamic wrapper accessed as ViewBag.Title.
    • Shared storage: Setting ViewBag.Title makes the value available through ViewData["Title"] during the same request.
  2. TempData:
    • Cross-request storage: TempData["Message"] survives a redirect, making it suitable for “Product saved” notifications.
    • Read behavior: A normal read marks the entry for deletion; Peek() reads without marking, and Keep() preserves it.
    • Provider: The default cookie-based provider serializes temporary values into protected cookies, so data should remain small.
  • Preferred approach: Core page data should use a strongly typed model because compile-time checking is safer than string keys.

D. Models

A model represents domain data, action input, or view-specific information and can include validation metadata.

  • Domain model: Represents a business entity such as Product.
  • Input model: Contains only fields accepted from a form, reducing over-posting risks.
  • View model: Combines exactly the values needed by a view, such as a product and category list.
  • Properties: Public writable properties such as Name and Price participate in model binding.
  • Data annotations: Attributes including [Required], [StringLength(80)], and [Range(0.01, 100000)] express validation rules.
  • Separation: Entity classes used by a database need not be exposed directly to browser forms.

IV. State and Forms — Preserving Context and Receiving Input

A. Session and State Management

Because HTTP is stateless, ASP.NET Core uses explicit mechanisms to preserve information between requests.

  • Cookies: Small client-side name-value data; authentication cookies should be HttpOnly, Secure, and configured with an appropriate SameSite policy.
  • Session: Server-associated data identified by a session cookie; enable it using AddSession() and UseSession().
  • Session API: HttpContext.Session.SetString("CartId", "C42") stores a string, while GetString("CartId") retrieves it.
  • TempData: Suitable for one-time information across a redirect, not permanent user data.
  • Hidden fields and query strings: Preserve page-specific values but are user-controlled and must never be trusted without validation.
  • Distributed deployment: Multiple servers require a shared session backing store, such as Redis, rather than independent in-memory stores.
  • Limitation: Session should contain identifiers or small values, not large object graphs or authoritative security data.

B. ASP.NET Core Forms

Forms collect browser input and normally submit it to a controller action using HTTP GET or POST.

  1. GET forms: Place values in the query string and suit searches or filters because the resulting URL can be bookmarked.
  2. POST forms: Place values in the request body and suit create or update operations.
  • Anti-forgery protection: Form Tag Helpers generate a token for POST forms, and [ValidateAntiForgeryToken] verifies it against cross-site request forgery.
  • Post/Redirect/Get: After a successful POST, redirecting to another action prevents accidental resubmission during refresh.
  • File upload: The form requires enctype="multipart/form-data", and the action can receive an IFormFile.
  • Security boundary: Posted identifiers, prices, roles, and ownership claims must be checked on the server.

V. Form Processing — Binding, Helpers, and Validation

A. Model Binding

Model binding converts request values into action parameters or object properties before the action executes.

  • Sources: Route values, form fields, and query strings are common sources; attributes such as [FromRoute], [FromQuery], and [FromForm] select one explicitly.
  • Name matching: An input named Name binds to ProductInput.Name; matching is case-insensitive.
  • Type conversion: Text "25.50" can become a decimal; failed conversion adds an error to ModelState.
  • Complex binding: Names such as Address.City bind nested objects, while Items[0].Name binds collection elements.
  • Over-posting defense: Use a restricted input model rather than binding a database entity containing fields such as IsAdmin.
CSHARP
[HttpPost]
[ValidateAntiForgeryToken]
public IActionResult Create(ProductInput input)
{
    if (!ModelState.IsValid)
        return View(input);

    service.Create(input);
    return RedirectToAction(nameof(Index));
}

B. Tag Helpers

Tag Helpers enhance familiar HTML elements with server-side behavior while keeping Razor markup readable.

  • Activation: @addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers commonly appears in _ViewImports.cshtml.
  • Form generation: <form asp-action="Create" method="post"> generates the action URL and normally an anti-forgery field.
  • Input generation: <input asp-for="Name"> derives its name, id, value, type, and validation attributes from model metadata.
  • Navigation: <a asp-controller="Products" asp-action="Details" asp-route-id="5"> generates a route-aware link.
  • Error display: <span asp-validation-for="Name"></span> renders the message associated with the Name field.
  • Advantage: Route and property changes are less likely to leave hard-coded URLs or field names inconsistent.

C. Server-Side Form Validations

Server-side validation is the authoritative check because browser-supplied data can be altered or submitted without JavaScript.

  • Annotation rules: [Required], [EmailAddress], [StringLength], [Range], and [Compare] describe common constraints.
  • Validation result: Binding and validation errors are stored in ModelState; ModelState.IsValid is false when any rule fails.
  • Custom errors: ModelState.AddModelError("Price", "Price must exceed cost.") handles business-specific rules.
  • Display: asp-validation-summary="ModelOnly" shows model-level errors, while asp-validation-for shows field-level errors.
  • Database rules: Uniqueness and concurrency must still be enforced by database constraints or transaction logic.
  • Failure path: Return the same view with the submitted model so Razor can redisplay values and messages.

D. Client-Side Form Validations

Client-side validation provides immediate browser feedback but supplements rather than replaces server-side validation.

  • Generated rules: Tag Helpers translate supported data annotations into data-val-* HTML attributes.
  • Libraries: ASP.NET Core MVC templates commonly use jQuery Validation and jQuery Validation Unobtrusive to interpret those attributes.
  • User experience: A missing required field can be reported before an HTTP request is sent, reducing avoidable round trips.
  • Consistency: The same model annotations can drive both generated client rules and server validation.
  • Limitation: Users can disable JavaScript, edit HTML, or send requests directly; therefore, the server must revalidate every submission.
  • Dynamic forms: Inputs added after page load may require unobtrusive validation to be reparsed before client rules apply.