ASP.NET MVC

ASP.NET MVC is a web application framework developed by Microsoft that implements the model-view-controller (MVC) pattern. It provides an alternative to ASP.NET Web Forms for building web applications, offering more control over HTML, better separation of concerns, and testability.

Key Components of ASP.NET MVC

  1. Model:
    Represents the application data and business logic. Models contain the core application logic and data.
  2. View:
    Handles the UI display (typically HTML templates). Views are responsible for presenting data to the user.
  3. Controller:
    Processes incoming requests, works with models, and selects views. Controllers handle user input and interaction.

Main Features

How ASP.NET MVC Works

  1. A user makes a request to the application
  2. Routing system determines which controller to use
  3. Controller processes the request (possibly interacting with models)
  4. Controller selects a view to render
  5. View generates HTML response sent back to the user

Advantages Over Web Forms

Feature ASP.NET MVC Web Forms
HTML Control Full control over rendered HTML Limited control (server controls)
Performance Better (no view state overhead) View state adds overhead
Testability Highly testable Harder to test
URLs Clean, SEO-friendly File extensions in URLs
Modern Web Better support for REST, AJAX Postback model
Note: ASP.NET MVC has evolved over the years, with the latest version being part of ASP.NET Core (now called just "ASP.NET Core MVC").

MVC Request Lifecycle

1. Routing → 2. Controller Initialization → 3. Action Execution → 
4. View Rendering → 5. Response

When to Use ASP.NET MVC

MVC Architecture (Model-View-Controller)

MVC is a software design pattern that separates an application into three main logical components: Model, View, and Controller. This separation helps manage complexity in large applications.

Model

Represents the data and business logic of the application

Responsibilities:

  • Manages application data
  • Contains business logic
  • Handles data validation
  • Interacts with database
  • Notifies views of changes

Example:

public class Product
{
    public int Id { get; set; }
    public string Name { get; set; }
    public decimal Price { get; set; }
    
    public bool IsExpensive()
    {
        return Price > 1000;
    }
}

View

Presents the data to the user and handles user interface

Responsibilities:

  • Displays data from model
  • Handles user interface
  • Receives user input
  • No business logic
  • Uses Razor syntax in ASP.NET

Example (Razor View):

@model Product
<h2>@Model.Name</h2>
<p>Price: $@Model.Price</p>
@if(Model.IsExpensive())
{
    <span class="warning">Premium Product</span>
}

Controller

Handles user requests and coordinates between Model and View

Responsibilities:

  • Processes user requests
  • Works with model
  • Selects appropriate view
  • Handles input validation
  • Manages application flow

Example:

public class ProductController : Controller
{
    public ActionResult Details(int id)
    {
        var product = _repository.GetProduct(id);
        if(product == null)
            return HttpNotFound();
            
        return View(product);
    }
}

How MVC Components Interact

Component Interacts With Direction Purpose
Controller ↔ View Controller passes model to View One-way (typically) Display data
Controller ↔ Model Controller updates/reads Model Two-way Business logic execution
View → Controller View sends user actions One-way User input handling
Key Points:
  • Models know nothing about Views or Controllers
  • Views contain minimal logic (only presentation)
  • Controllers shouldn't contain business logic (should be in Model)
  • Components are loosely coupled

MVC Request Flow

1. User Request → 2. Routing → 3. Controller Initialization → 
4. Controller Action → 5. Model Interaction → 6. View Selection → 
7. View Rendering → 8. Response

Benefits of MVC Architecture

  1. Separation of Concerns: Clean division of responsibilities
  2. Testability: Components can be tested independently
  3. Maintainability: Easier to modify one component without affecting others
  4. Parallel Development: Multiple developers can work simultaneously
  5. Flexibility: Views can be changed without modifying business logic

ASP.NET MVC Specifics

Typical File Structure:

/Controllers
    ProductController.cs
    HomeController.cs
/Models
    Product.cs
    Order.cs
/Views
    /Product
        Index.cshtml
        Details.cshtml
    /Shared
        _Layout.cshtml

Common Mistakes to Avoid

  • Putting business logic in Views or Controllers
  • Making Models too "dumb" (anemic domain model)
  • Creating overly complex Views with too much logic
  • Making Controllers too large (fat controller anti-pattern)
  • Tight coupling between components

ASP.NET MVC vs Web Forms

Feature ASP.NET MVC Web Forms
Architecture Model-View-Controller (MVC) pattern Event-driven model (similar to WinForms)
Control Over HTML Full control over rendered HTML Limited control (uses server controls)
State Management Stateless (no view state) Uses ViewState and PostBack
URL Structure Clean, RESTful URLs (Routing) File-based URLs (.aspx extensions)
Testability Highly testable (unit testing friendly) Difficult to unit test
Performance Faster (lighter weight, no view state) Slower (view state overhead)
Development Style Separation of concerns Rapid Application Development (RAD)
Learning Curve Steeper (requires understanding of patterns) Easier for beginners
Page Lifecycle Simple request/response Complex page lifecycle events
Modern Web Support Better for AJAX, REST APIs, SPAs Designed for traditional web apps
Community & Future Active development (part of ASP.NET Core) Maintenance mode (not in .NET Core)

Key Differences Explained

1. Architecture Approach

MVC (Separation of Concerns)
  • Clear separation between UI, logic, and data
  • Better for large, complex applications
  • Follows SOLID principles
Web Forms (RAD Model)
  • Rapid development with drag-and-drop
  • Tight coupling between UI and logic
  • Good for simple applications

2. State Management Comparison

MVC (Stateless)
// No automatic state persistence
// Uses HTTP verbs explicitly:
[HttpPost]
public ActionResult Create(Product product)
{
    // Handle form submission
}
Web Forms (Stateful)
// Automatic state management
protected void Button_Click(object sender, EventArgs e)
{
    // Control values persist automatically
    Label1.Text = TextBox1.Text;
}

When to Use Each

Choose ASP.NET MVC When:

  • You need full control over HTML/CSS/JavaScript
  • Building RESTful services or APIs
  • Developing large, complex applications
  • Test-driven development (TDD) is important
  • Creating mobile-friendly or responsive designs
  • Working with modern JavaScript frameworks

Choose Web Forms When:

  • Migrating legacy Windows Forms applications
  • Rapid prototyping is needed
  • Developers are familiar with event-driven model
  • Maintaining existing Web Forms applications
  • Simple data-entry applications

Code Comparison

Simple Form Submission

MVC Approach
// Controller
[HttpPost]
public ActionResult Register(User user)
{
    if(ModelState.IsValid)
    {
        _service.Register(user);
        return RedirectToAction("Success");
    }
    return View(user);
}

// View (Razor)
@model User
@using (Html.BeginForm())
{
    @Html.TextBoxFor(m => m.Username)
    @Html.ValidationMessageFor(m => m.Username)
    <input type="submit" value="Register" />
}
Web Forms Approach
// Code-behind
protected void btnRegister_Click(object sender, EventArgs e)
{
    if(Page.IsValid)
    {
        var user = new User {
            Username = txtUsername.Text
        };
        _service.Register(user);
        Response.Redirect("Success.aspx");
    }
}

// ASPX Page
<asp:TextBox ID="txtUsername" runat="server" />
<asp:RequiredFieldValidator 
    ControlToValidate="txtUsername"
    runat="server" ErrorMessage="Required" />
<asp:Button ID="btnRegister" 
    runat="server" Text="Register"
    OnClick="btnRegister_Click" />

Migration Considerations

  • Web Forms to MVC migration requires significant redesign
  • Server controls don't exist in MVC
  • ViewState concepts don't apply to MVC
  • Event handlers need to be converted to controller actions
  • Consider hybrid approach (MVC and Web Forms together) for gradual migration

Performance Comparison

Metric ASP.NET MVC Web Forms
Memory Usage Lower (no view state) Higher (view state storage)
Request Processing Faster (leaner pipeline) Slower (complex lifecycle)
Page Size Smaller (clean HTML) Larger (view state, control IDs)
Scalability Better (stateless) Good (but stateful)

ASP.NET MVC Application Folder Structure

The MVC framework enforces a convention-based folder structure that promotes organization and separation of concerns.

MVC_Application/
├── App_Data/                     # Database files, XML storage, etc.
├── App_Start/                    # Configuration classes
│   ├── BundleConfig.cs         # Script/CSS bundling
│   ├── FilterConfig.cs         # Global filters
│   ├── RouteConfig.cs          # URL routing rules
│   └── WebApiConfig.cs         # Web API configuration
│
├── Controllers/                  # Controller classes
│   ├── HomeController.cs       # Default controller
│   ├── AccountController.cs    # Authentication controller
│   └── ProductController.cs    # Example business controller
│
├── Models/                      # Business logic and data models
│   ├── Product.cs              # Domain model
│   ├── AccountViewModels.cs    # View-specific models
│   └── Repository.cs           # Data access layer
│
├── Views/                       # Razor view files (.cshtml)
│   ├── Home/                   # Views for HomeController
│   │   ├── Index.cshtml        # Default view
│   │   └── About.cshtml        # Secondary view
│   │
│   ├── Account/                # Views for AccountController
│   │   ├── Login.cshtml        
│   │   └── Register.cshtml     
│   │
│   ├── Product/                # Views for ProductController
│   │   ├── Index.cshtml        # List view
│   │   ├── Details.cshtml      # Detail view
│   │   └── Edit.cshtml         # Edit form
│   │
│   ├── Shared/                 # Reusable components
│   │   ├── _Layout.cshtml      # Master page
│   │   ├── _Navigation.cshtml  # Partial view
│   │   └── Error.cshtml        # Error page
│   │
│   └── Web.config              # View-specific config
│
├── Scripts/                     # JavaScript files
│   ├── jquery-{version}.js     
│   ├── modernizr-{version}.js  
│   └── site.js                 # Application scripts
│
├── Content/                     # CSS and static assets
│   ├── Site.css                # Main stylesheet
│   └── Images/                 # Application images
│
├── Areas/                      # Logical sections (optional)
│   ├── Admin/                 # Admin section
│   │   ├── Controllers/        
│   │   ├── Models/             
│   │   └── Views/              
│   └── API/                   # Web API section
│
├── Global.asax                 # Application lifecycle events
└── Web.config                  # Application configuration

Key Folder Explanations

Folder Purpose Important Files
App_Start Configuration classes executed at application startup RouteConfig.cs, BundleConfig.cs
Controllers Contains controller classes that handle requests [Name]Controller.cs files
Views Contains Razor views organized by controller .cshtml files, _Layout.cshtml
Models Contains business logic and data models Domain models, ViewModels
Areas Separate functional sections of the application Admin, API sections

View Subfolder Convention

Views are organized in subfolders that must match controller names:

/Views
   /Home          ← For HomeController
      Index.cshtml
   /Product       ← For ProductController
      Index.cshtml
      Details.cshtml

The framework automatically looks for views in these corresponding folders.

Special View Files

_Layout.cshtml

Master page template containing common HTML structure

<!DOCTYPE html>
<html>
<head>
    @RenderSection("styles", required: false)
</head>
<body>
    @RenderBody()
    @RenderSection("scripts", required: false)
</body>
</html>
_ViewStart.cshtml

Executes before any view to set default layout

@{
    Layout = "~/Views/Shared/_Layout.cshtml";
}
_ViewImports.cshtml

Contains common directives for all views

@using MyApplication.Models
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers

Important Notes

  • Don't rename the standard folders (MVC relies on these conventions)
  • Keep business logic out of Views (only presentation logic)
  • Use Areas to organize large applications into modules
  • Web.config in Views folder prevents direct access to .cshtml files
  • App_Data is the only folder with write permissions by default

Typical File Naming Conventions

Component Naming Pattern Example
Controllers [Name]Controller.cs ProductController.cs
Views ActionName.cshtml Index.cshtml, Details.cshtml
Layouts _Layout.cshtml _Layout.cshtml, _AdminLayout.cshtml
Partial Views _PartialName.cshtml _ProductTable.cshtml
View Models [Purpose]ViewModel.cs ProductEditViewModel.cs

What is a Model in ASP.NET MVC?

The Model represents the application's data and business logic in the MVC (Model-View-Controller) architecture. It encapsulates the application state and rules for manipulating that state.

Key Responsibilities of a Model

  1. Data Representation
    Defines the structure of your application data (entities, properties, relationships)
  2. Business Logic
    Contains validation rules, calculations, and business processes
  3. Data Access
    Handles communication with databases or other data sources
  4. State Management
    Maintains and manages the application's current state

Types of Models in ASP.NET MVC

Type Purpose Example
Domain Model Core business entities Product, Customer, Order
View Model Data shaped for specific views ProductEditViewModel
Data Transfer Object (DTO) Data structure for API communication ProductApiResponse

Example: Domain Model

public class Product
{
    public int Id { get; set; }
    
    [Required(ErrorMessage = "Name is required")]
    [StringLength(100)]
    public string Name { get; set; }
    
    [Range(0.01, 10000)]
    public decimal Price { get; set; }
    
    public bool IsInStock { get; set; }
    
    // Business logic method
    public bool IsExpensive() 
    {
        return Price > 1000;
    }
}

Example: View Model

public class ProductCreateViewModel
{
    [Display(Name = "Product Name")]
    public string Name { get; set; }
    
    [DataType(DataType.Currency)]
    public decimal Price { get; set; }
    
    // Additional view-specific properties
    public List<SelectListItem> Categories { get; set; }
    public int SelectedCategoryId { get; set; }
}

Model Validation

Data Annotations for Validation

public class UserRegistrationModel
{
    [Required]
    [EmailAddress]
    public string Email { get; set; }
    
    [Required]
    [StringLength(100, MinimumLength = 6)]
    [DataType(DataType.Password)]
    public string Password { get; set; }
    
    [Compare("Password", ErrorMessage = "Passwords don't match")]
    public string ConfirmPassword { get; set; }
}
Common Data Annotations:
  • [Required] - Field is mandatory
  • [StringLength] - Limits string length
  • [Range] - Value must be between specified numbers
  • [EmailAddress] - Validates email format
  • [RegularExpression] - Custom pattern matching

Model Best Practices

  1. Keep Models Focused

    Each model should represent a single concept or entity

  2. Separate Concerns

    Use different models for domain logic vs. view representation

  3. Validation in Models

    Place validation rules in models (not controllers or views)

  4. Fat Models, Thin Controllers

    Business logic belongs in models, not controllers

  5. Use ViewModels

    Create specific models for views when needed

Common Model Mistakes

  • Putting presentation logic in domain models
  • Making "anemic" models with no behavior
  • Directly using domain models in views
  • Mixing data access code with business logic

Model in MVC Flow

Request → Controller → Model (Business Logic/Data Access) → Controller → View
       ↑_________________________________________________________↓
Key Points:
  • Models are unaware of Views and Controllers
  • Controllers interact with Models to process data
  • Views receive data from Models (via Controllers)
  • Models should be testable independently

Data Annotations & Validation in ASP.NET MVC

Data Annotations are attributes used to add metadata and validation rules to model properties. They provide a declarative way to define validation requirements that are enforced both client-side and server-side.

Benefits of Data Annotations

  • Centralized validation rules with model definitions
  • Automatic client-side validation generation
  • Consistent validation across all application layers
  • Built-in support for error message localization
  • Seamless integration with ASP.NET MVC validation infrastructure

Common Validation Attributes

Attribute Purpose Example
[Required] Ensures the property has a value
[Required(ErrorMessage="Name is required")]
[StringLength] Specifies minimum and maximum string length
[StringLength(50, MinimumLength=3)]
[Range] Constrains value to a specified range
[Range(18, 120)]
[RegularExpression] Validates against a regex pattern
[RegularExpression(@"^\d{3}-\d{3}-\d{4}$")]
[EmailAddress] Validates email format
[EmailAddress]
[Compare] Compares two property values
[Compare("Password")]
[DataType] Specifies data type for UI hints
[DataType(DataType.Password)]
[Display] Specifies display name
[Display(Name="Full Name")]

Validation Implementation

Model with Data Annotations

public class UserRegistrationModel
{
    [Required(ErrorMessage = "Email is required")]
    [EmailAddress(ErrorMessage = "Invalid email format")]
    [Display(Name = "Email Address")]
    public string Email { get; set; }

    [Required]
    [StringLength(100, MinimumLength = 8, 
        ErrorMessage = "Password must be 8-100 characters")]
    [DataType(DataType.Password)]
    public string Password { get; set; }

    [DataType(DataType.Password)]
    [Display(Name = "Confirm Password")]
    [Compare("Password", 
        ErrorMessage = "Passwords do not match")]
    public string ConfirmPassword { get; set; }

    [Range(typeof(bool), "true", "true", 
        ErrorMessage = "Must accept terms")]
    [Display(Name = "Accept Terms")]
    public bool AcceptTerms { get; set; }
}

Controller Action with Validation

[HttpPost]
public ActionResult Register(UserRegistrationModel model)
{
    if (ModelState.IsValid)
    {
        // Process valid data
        return RedirectToAction("Success");
    }
    
    // Return to form with validation errors
    return View(model);
}

View with Validation Helpers

@model UserRegistrationModel

@using (Html.BeginForm())
{
    <div class="form-group">
        @Html.LabelFor(m => m.Email)
        @Html.TextBoxFor(m => m.Email, new { @class = "form-control" })
        @Html.ValidationMessageFor(m => m.Email)
    </div>
    
    <div class="form-group">
        @Html.LabelFor(m => m.Password)
        @Html.PasswordFor(m => m.Password, new { @class = "form-control" })
        @Html.ValidationMessageFor(m => m.Password)
    </div>
    
    <!-- Other fields -->
    
    <input type="submit" value="Register" class="btn btn-primary" />
}

Custom Validation Attributes

Creating Custom Validators

public class FutureDateAttribute : ValidationAttribute
{
    public override bool IsValid(object value)
    {
        if (value is DateTime date)
        {
            return date > DateTime.Now;
        }
        return false;
    }
}

// Usage:
[FutureDate(ErrorMessage = "Date must be in the future")]
public DateTime EventDate { get; set; }

Model-Level Validation

public class EventModel : IValidatableObject
{
    public DateTime StartDate { get; set; }
    public DateTime EndDate { get; set; }
    
    public IEnumerable<ValidationResult> Validate(
        ValidationContext validationContext)
    {
        if (EndDate < StartDate)
        {
            yield return new ValidationResult(
                "End date must be after start date",
                new[] { nameof(EndDate) });
        }
    }
}

Client-Side Validation

Enabling Client-Side Validation:
  1. Include these scripts in your layout:
    <script src="~/lib/jquery-validation/dist/jquery.validate.min.js"></script>
    <script src="~/lib/jquery-validation-unobtrusive/jquery.validate.unobtrusive.min.js"></script>
  2. Ensure appsettings.json has:
    "ClientValidationEnabled": true,
    "UnobtrusiveJavaScriptEnabled": true

Validation Best Practices

  • Always validate on both client and server sides
  • Use specific error messages for better UX
  • Create custom validators for complex rules
  • Localize validation messages for multilingual apps
  • Keep validation logic in models (not controllers)

Common Validation Mistakes

  • Relying solely on client-side validation
  • Placing validation logic in controllers
  • Not handling ModelState errors properly
  • Using overly generic error messages
  • Forgetting to include validation scripts

Validation Workflow

1. User submits form → 
2. Client-side validation (if enabled) → 
3. Server receives request → 
4. Model binding with validation → 
5. Controller checks ModelState.IsValid → 
6. Either processes data or returns errors → 
7. View displays validation messages

Model Binding in ASP.NET MVC

Automatic mapping of HTTP request data to action parameters and model properties

What is Model Binding?

Model Binding is a fundamental feature of ASP.NET MVC that automatically:

  • Extracts data from incoming HTTP requests (form fields, query strings, route data, JSON)
  • Converts string values to appropriate .NET data types (int, DateTime, bool, etc.)
  • Populates controller action parameters or model object properties
  • Handles complex object graphs and collections

Why Should We Use Model Binding?

  1. Saves Development Time: Eliminates manual data extraction from requests
  2. Reduces Boilerplate Code: No need to write repetitive parsing logic
  3. Improves Maintainability: Centralized and consistent data handling
  4. Enables Strong Typing: Works directly with your domain models
  5. Supports Validation: Integrates seamlessly with data annotations

How Model Binding Works

  1. Request Receipt: MVC receives an HTTP request (GET/POST/PUT)
  2. Parameter Matching: Framework matches request data to parameter names
  3. Type Conversion: Converts string values to specified .NET types
  4. Validation: Checks data annotations if present on models
  5. Population: Creates and populates the target object(s)
  6. Controller Access: Fully populated object passed to action method

Data Binding Sources (Priority Order)

Source Description When Used
Form Values POSTed form fields (application/x-www-form-urlencoded or multipart/form-data) Form submissions, file uploads
Route Values URL path segments (/{controller}/{action}/{id}) Clean URLs, RESTful routes
Query Strings URL parameters (?name=value&page=1) GET requests, filtering data
JSON Body Request body (application/json) API requests, AJAX calls

Explicit Binding with Attributes

Control binding behavior using these attributes:

// Bind from specific sources
public ActionResult GetUser(
    [FromQuery] string searchTerm,    // From URL query string
    [FromRoute] int id,               // From route parameters
    [FromForm] User model,            // From form fields
    [FromBody] Order order,           // From request body (JSON/XML)
    [FromHeader(Name="Accept")] string acceptHeader // From headers
) { ... }

Complex Object Binding

Model Binding automatically handles:

  • Nested objects (object graphs)
  • Collections (List<T>, arrays)
  • Dictionaries
public class OrderViewModel {
    public Customer Customer { get; set; }
    public List<OrderItem> Items { get; set; }
    public Dictionary<string, string> Metadata { get; set; }
}

// Automatically binds complex object from form/JSON
[HttpPost]
public ActionResult PlaceOrder(OrderViewModel order) { ... }

Model Validation with Binding

Works automatically with DataAnnotations:

public class RegisterModel {
    [Required(ErrorMessage = "Email is required")]
    [EmailAddress]
    public string Email { get; set; }

    [Required]
    [StringLength(100, MinimumLength = 6)]
    [DataType(DataType.Password)]
    public string Password { get; set; }

    [Compare("Password", ErrorMessage = "Passwords don't match")]
    public string ConfirmPassword { get; set; }
}

[HttpPost]
public ActionResult Register(RegisterModel model) {
    if (ModelState.IsValid) {
        // Process valid data
    }
    return View(model);
}

Model Binding Best Practices

  1. Use ViewModels instead of domain models for binding
  2. Always check ModelState.IsValid in POST actions
  3. Use explicit binding attributes ([FromForm], [FromBody]) for clarity
  4. Keep binding models simple and focused
  5. Implement custom model binders for special cases

Strongly Typed Views in ASP.NET MVC

Views that are bound to specific model types for compile-time safety and IntelliSense support

What are Strongly Typed Views?

Strongly typed views are Razor views that:

  • Declare a specific model type using @model directive
  • Provide compile-time type checking
  • Enable Visual Studio IntelliSense
  • Reduce runtime errors
  • Improve code maintainability

Basic Strongly Typed View

@model MyApplication.Models.Product

<h2>@Model.Name</h2>
<p>Price: @Model.Price.ToString("C")</p>
<p>In Stock: @Model.InStock</p>

@* IntelliSense works on Model.* properties *@

Benefits of Strongly Typed Views

  1. Compile-Time Safety: Catches type mismatches during compilation
  2. IntelliSense Support: Visual Studio suggests properties/methods
  3. Refactoring Support: Property renames update in views
  4. Improved Readability: Clear what data the view expects
  5. Better Tooling: Works well with scaffolding and code generation

Strongly Typed HTML Helpers

Helpers that work with model properties:

@model MyApplication.Models.User

@using (Html.BeginForm())
{
    <div class="form-group">
        @Html.LabelFor(m => m.FirstName)
        @Html.TextBoxFor(m => m.FirstName, new { @class = "form-control" })
        @Html.ValidationMessageFor(m => m.FirstName)
    </div>
    
    <div class="form-group">
        @Html.LabelFor(m => m.Email)
        @Html.TextBoxFor(m => m.Email, new { @class = "form-control" })
        @Html.ValidationMessageFor(m => m.Email)
    </div>
}

Using ViewModels with Strongly Typed Views

// ViewModel definition
public class ProductDetailViewModel
{
    public Product Product { get; set; }
    public List<Review> Reviews { get; set; }
    public bool ShowAdminControls { get; set; }
}

// Controller action
public ActionResult Detail(int id)
{
    var viewModel = new ProductDetailViewModel
    {
        Product = _repository.GetProduct(id),
        Reviews = _repository.GetReviews(id),
        ShowAdminControls = User.IsInRole("Admin")
    };
    return View(viewModel);
}

// View
@model MyApplication.ViewModels.ProductDetailViewModel

<h2>@Model.Product.Name</h2>

@if(Model.ShowAdminControls)
{
    @Html.ActionLink("Edit", "Edit", new { id = Model.Product.Id })
}

<h3>Reviews (@Model.Reviews.Count)</h3>
@foreach(var review in Model.Reviews)
{
    <div>@review.Text</div>
}

Working with Collections

@model List<MyApplication.Models.Product>

<table class="table">
    <tr>
        <th>Name</th>
        <th>Price</th>
    </tr>
    @foreach(var product in Model)
    {
        <tr>
            <td>@product.Name</td>
            <td>@product.Price.ToString("C")</td>
        </tr>
    }
</table>

Best Practices for Strongly Typed Views

  1. Always specify @model at the top of your view
  2. Use ViewModels to customize data for views
  3. Prefer @Html.EditorFor and @Html.DisplayFor templates
  4. Keep view logic minimal - move complex logic to helpers or controllers
  5. Use partial views for reusable components

Strongly Typed Partial Views

// Partial view definition (_ProductCard.cshtml)
@model MyApplication.Models.Product

<div class="product-card">
    <h3>@Model.Name</h3>
    <p>@Model.Price.ToString("C")</p>
    @Html.ActionLink("Details", "Details", new { id = Model.Id })
</div>

// Using the partial in main view
@foreach(var product in Model.Products)
{
    @Html.Partial("_ProductCard", product)
}

Editor Templates with Strong Types

// In Views/Shared/EditorTemplates/Product.cshtml
@model MyApplication.Models.Product

<div class="form-group">
    @Html.LabelFor(m => m.Name)
    @Html.TextBoxFor(m => m.Name, new { @class = "form-control" })
</div>

// In main view
@model MyApplication.Models.Product

@using (Html.BeginForm())
{
    @Html.EditorForModel()  // Uses the editor template
    
    <input type="submit" value="Save" />
}

ViewModels vs Models in ASP.NET MVC

Key Differences

Aspect Domain Models ViewModels
Purpose Represent business/data layer entities Shape data specifically for views
Scope Application-wide business logic View-specific presentation logic
Structure Mirrors database tables/entities Optimized for UI requirements
Validation Business rule validation UI input validation
Usage Used throughout application layers Used only between controller and view

Domain Model Example

public class Product 
{
    public int Id { get; set; }
    public string Name { get; set; }
    public decimal Price { get; set; }
    public int CategoryId { get; set; }
    public Category Category { get; set; }
    
    // Business logic
    public bool IsPremium() => Price > 1000;
}

ViewModel Example

public class ProductViewModel
{
    public int Id { get; set; }
    
    [Required]
    [Display(Name = "Product Name")]
    public string Name { get; set; }
    
    [Range(0.01, 10000)]
    public decimal Price { get; set; }
    
    // View-specific properties
    public List<SelectListItem> Categories { get; set; }
    public int SelectedCategoryId { get; set; }
    
    // UI helper properties
    public bool ShowDiscount { get; set; }
    public string FormattedPrice => Price.ToString("C");
}

When to Use Domain Models

  • Working with business logic and data access
  • The entity maps directly to a database table
  • The data structure matches the view requirements exactly
  • Creating reusable core application components

When to Use ViewModels

  • When view needs different data than domain model provides
  • To combine data from multiple domain models
  • When you need view-specific properties (dropdown lists, formatted values)
  • To prevent over-posting attacks
  • When you need to flatten complex object graphs

Best Practices

  1. Keep domain models focused on business logic
  2. Use ViewModels to adapt domain models for views
  3. Never expose domain models directly to views
  4. Automate mapping between models and ViewModels (AutoMapper)
  5. Keep ViewModels lean and view-specific

Common Mistakes

  • Using domain models directly in views (security risk)
  • Putting presentation logic in domain models
  • Making ViewModels too complex (should be view-specific)
  • Not using proper mapping between layers
  • Creating "anemic" domain models with no behavior