L'architettura Model-View-Controller (MVC) è un modello di design testuale che separa le preoccupazioni all'interno di un'applicazione web, rendendo più facile gestire la complessità, i componenti di prova in isolamento e le caratteristiche di scala nel tempo. In ASP.NET Core, MVC è un cittadino di prima classe, fornendo un quadro robusto per la costruzione di applicazioni web moderne e manutenbili.

Comprendere il modello MVC in profondità

Prima di immergersi in codice, è essenziale capire come i tre componenti fondamentali di MVC collaborano per gestire una richiesta dell'utente.

  • Modello[]: Rappresenta la struttura dei dati e le regole aziendali. Non sa dell'interfaccia utente o come vengono visualizzati i dati. I modelli sono in genere semplici classi C# che incapsulano proprietà, logica di validazione e accesso ai dati (spesso tramite Entity Framework Core).
  • Visualizza[]: Renders l'interfaccia utente. In ASP.NET Core, le visualizzazioni sono file Razor (`.cshtml`) che combinano il markup HTML con il codice C# lato server.
  • Controller]: agisce come intermediario. Riceve richieste HTTP, decide quale modello utilizzare e seleziona la visualizzazione appropriata per tornare. I controller contengono metodi di azione che mappano le rotte specifiche.

La richiesta tipica scorre in ASP.NET Core MVC: un utente naviga in un URL (ad esempio [), il middleware instradante dirige la richiesta all'azione [, l'azione interagisce con il modello (ad esempio, fetches prodotti da un database), imballa i dati in un modello di visualizzazione e lo passa alla vista.

Prerequisiti

  • .NET SDK[] (versione 6.0 o successiva). Scarica da dotnet.microsoft.com.
  • Visual Studio[], Codice Studio Visuale[], o qualsiasi editor di codice preferito.
  • La familiarità di base con C# e i concetti di sviluppo web.

Passo 1: Creazione di un nuovo progetto MVC di ASP.NET Core

Puoi iniziare con il .NET CLI o Visual Studio. Entrambi forniscono un modello di progetto che impalca la struttura standard della cartella MVC.

Usare la linea di comando

Aprire un terminale e eseguire:

dotnet new mvc -n MyMvcApp

Questo crea un progetto chiamato in una nuova cartella. La struttura generata include , , [], e (per file statici).

Utilizzo di Visual Studio

In Visual Studio, scegliere Crea un nuovo progetto[ → selezionare [ASP.NET Core Web App (Model-View-Controller)] → configurare il nome del progetto e la posizione → scegliere la versione .NET (ad esempio, .NET 8). Le stesse cartelle vengono create automaticamente.

Verificare le funzioni del progetto:

cd MyMvcApp
dotnet run

Apri per vedere la home page predefinita.

Fase 2: Comprendere la struttura del progetto

Il progetto impalcabile contiene diversi elementi chiave:

  • Controllers[: cartella vuota dove aggiungere le classi di controllo C#.
  • Models[]]: Luogo per le classi di dominio e modelli di visualizzazione.
  • Visualizza[]]: Ha una cartella e [] per impostazione predefinita, più un layout.
  • Program.cs[]: Avvio di applicazioni, dove i servizi (compresi MVC) sono configurati.

Aprire e notare le linee che permettono MVC:

var builder = WebApplication.CreateBuilder(args);
builder.Services.AddControllersWithViews();
var app = builder.Build();
...
app.MapControllerRoute(
 name: "default",
 pattern: "{controller=Home}/{action=Index}/{id?}");
app.Run();

Questo imposta la rotta predefinita che mappa URL come ] a .

Passo 3: Creazione di una classe di modello

I modelli rappresentano i dati con cui l'applicazione funziona. Inizia creando un modello [ all'interno della cartella .

// Models/Product.cs
namespace MyMvcApp.Models;

public class Product
{
 public int Id { get; set; }
 public string Name { get; set; } = string.Empty;
 public decimal Price { get; set; }
 public string? Description { get; set; }
 public DateTime CreatedAt { get; set; } = DateTime.UtcNow;
}

È possibile arricchire i modelli con annotazioni di dati per la validazione:

using System.ComponentModel.DataAnnotations;

public class Product
{
 public int Id { get; set; }

 [Required(ErrorMessage = "Product name is required.")]
 [StringLength(100)]
 public string Name { get; set; } = string.Empty;

 [Range(0.01, 10000)]
 public decimal Price { get; set; }

 [MaxLength(500)]
 public string? Description { get; set; }

 [Display(Name = "Created")]
 public DateTime CreatedAt { get; set; }
}

In una vera applicazione, si aggiungerebbe tipicamente un contesto di database (Entity Framework Core) per persistere nei modelli. Per questa guida useremo i dati in memoria per mantenere la concentrazione sul flusso MVC.

Passo 4: Aggiungere un controller

I controller gestiscono le richieste in arrivo e orchestrano la risposta. Creare un all'interno della cartella .

// Controllers/ProductsController.cs
using Microsoft.AspNetCore.Mvc;
using MyMvcApp.Models;
using System.Collections.Generic;

namespace MyMvcApp.Controllers;

public class ProductsController : Controller
{
 // Simulate a data source
 private static List<Product> _products = new List<Product>
 {
 new Product { Id = 1, Name = "Laptop", Price = 999.99m },
 new Product { Id = 2, Name = "Smartphone", Price = 599.99m },
 new Product { Id = 3, Name = "Tablet", Price = 399.99m }
 };

 // GET: /Products
 public IActionResult Index()
 {
 return View(_products); // Pass list to the view
 }

 // GET: /Products/Details/5
 public IActionResult Details(int id)
 {
 var product = _products.Find(p => p.Id == id);
 if (product == null)
 return NotFound();
 return View(product);
 }

 // GET: /Products/Create
 public IActionResult Create()
 {
 return View();
 }

 // POST: /Products/Create
 [HttpPost]
 [ValidateAntiForgeryToken]
 public IActionResult Create(Product product)
 {
 if (ModelState.IsValid)
 {
 product.Id = _products.Max(p => p.Id) + 1;
 product.CreatedAt = DateTime.UtcNow;
 _products.Add(product);
 return RedirectToAction(nameof(Index));
 }
 return View(product);
 }
}

Punti chiave:

  • IActionResult[]] è il tipo di ritorno. Può essere un , [, , ecc.
  • I nomi di azione mappano a una cartella chiamata dal controller ([).
  • L'azione ha due sovraccarichi: uno per GET (vedi il modulo) e uno per POST (presentazione del modulo di manuale).
  • protegge contro la richiesta di falsificazione del sito.

Passo 5: Creazione di viste con Razor Syntax

Viste in diretta . Il layout condiviso è in .

Indice Visualizza – Visualizzare un elenco

Crea :

@model IEnumerable<MyMvcApp.Models.Product>
@{
 ViewData["Title"] = "Product List";
}

<h2>@ViewData["Title"]</h2>

<table class="table table-striped">
 <thead>
 <tr>
 <th>@Html.DisplayNameFor(model => model.Id)</th>
 <th>@Html.DisplayNameFor(model => model.Name)</th>
 <th>@Html.DisplayNameFor(model => model.Price)</th>
 <th></th>
 </tr>
 </thead>
 <tbody>
 @foreach (var item in Model)
 {
 <tr>
 <td>@item.Id</td>
 <td>@item.Name</td>
 <td>@item.Price.ToString("C")</td>
 <td>
 <a asp-action="Details" asp-route-id="@item.Id">Details</a>
 </td>
 </tr>
 }
 </tbody>
</table>

<p>
 <a asp-action="Create" class="btn btn-primary">Create New Product</a>
</p>

Punte di richiamo[]: Usa per passare dall'HTML al C#, e /[] tag helper per generare URL.

Dettagli Vedi

Crea :

@model MyMvcApp.Models.Product
@{
 ViewData["Title"] = "Product Details";
}

<h2>@Model.Name</h2>

<dl class="row">
 <dt class="col-sm-2">@Html.DisplayNameFor(model => model.Id)</dt>
 <dd class="col-sm-10">@Model.Id</dd>

 <dt class="col-sm-2">@Html.DisplayNameFor(model => model.Price)</dt>
 <dd class="col-sm-10">@Model.Price.ToString("C")</dd>

 <dt class="col-sm-2">@Html.DisplayNameFor(model => model.Description)</dt>
 <dd class="col-sm-10">@Model.Description</dd>

 <dt class="col-sm-2">@Html.DisplayNameFor(model => model.CreatedAt)</dt>
 <dd class="col-sm-10">@Model.CreatedAt</dd>
</dl>

<a asp-action="Index">Back to List</a>

Creare Vista con il modulo

Crea :

@model MyMvcApp.Models.Product
@{
 ViewData["Title"] = "Create Product";
}

<h2>Create</h2>

<form asp-action="Create">
 <div asp-validation-summary="ModelOnly" class="text-danger"></div>

 <div class="form-group">
 <label asp-for="Name"></label>
 <input asp-for="Name" class="form-control" />
 <span asp-validation-for="Name" class="text-danger"></span>
 </div>

 <div class="form-group">
 <label asp-for="Price"></label>
 <input asp-for="Price" class="form-control" />
 <span asp-validation-for="Price" class="text-danger"></span>
 </div>

 <div class="form-group">
 <label asp-for="Description"></label>
 <textarea asp-for="Description" class="form-control"></textarea>
 </div>

 <button type="submit" class="btn btn-primary">Create</button>
 <a asp-action="Index" class="btn btn-secondary">Cancel</a>
</form>

@section Scripts {
 @{await Html.RenderPartialAsync("_ValidationScriptsPartial");}
}

I supporti per tag razor come generano campi formali con binding e validazione del modello.

Passo 6: Aggiungere Routing e Percorsi personalizzati

MVC utilizza il routing convenzionato per impostazione predefinita. Il percorso in [] mappe []. È inoltre possibile aggiungere l'attributo routing per un maggiore controllo. Ad esempio, nel controller:

[Route("products")]
public class ProductsController : Controller
{
 [Route("")] // matches /products
 [Route("index")] // matches /products/index
 public IActionResult Index() { ... }

 [Route("{id:int}")] // matches /products/5
 public IActionResult Details(int id) { ... }
}

Questo approccio è utile per le API RESTful quando combinato con .

Passo 7: Utilizzo di ViewModels per dati complessi

Spesso è necessario passare più di un oggetto di dati a una vista, o includere proprietà extra (come liste selezionate, titoli di pagina).

namespace MyMvcApp.Models.ViewModels;

public class ProductIndexViewModel
{
 public IEnumerable<Product> Products { get; set; }
 public string SearchString { get; set; } = string.Empty;
 public decimal MaxPrice { get; set; } = 10000;
}

Quindi regolare l'azione del controller per populare il modello di vista e passarlo alla vista. La vista utilizza e accede alle proprietà di conseguenza.

Passo 8: Convalida di esecuzione

ASP.NET Core MVC fornisce sia la convalida lato server che lato client tramite annotazioni di dati. Aggiungi [], , e attributi personalizzati. Nella visualizzazione , il visualizza messaggi di errore. L'attributo sul modulo di presentazione assicura solo l'azione reale assicura che solo i messaggi di presentazione sono veriti.

Per la logica di validazione personalizzata, implementare sul modello o creare una classe di validazione separata. La documentazione ufficiale ASP.NET Core validation[] copre questi modelli in dettaglio.

Passo 9: iniezione di dipendenza nei regolatori

Invece di dati di codifica dura, è possibile iniettare servizi (come un contesto di repository o database) nel costruttore del controller, che promuove l'accoppiamento e la testabilità allentati.

public class ProductsController : Controller
{
 private readonly IProductRepository _repository;

 public ProductsController(IProductRepository repository)
 {
 _repository = repository;
 }

 public IActionResult Index()
 {
 var products = _repository.GetAll();
 return View(products);
 }
}

Registra il repository in :

builder.Services.AddScoped<IProductRepository, ProductRepository>();

Il metodo registra già i controller per DI. Questo modello rende la vostra applicazione più pulita e più manutenbile. Vedi Guida di iniezione di dipendenza di Microsoft[] per altro.

Passo 10: Lavorare con i layout e le viste parziali

Per personalizzare, modificare il in []]]. È possibile definire le sezioni, o utilizzare viste parziali per i componenti UI riutilizzabili come navigazione, piè di pagina o rendering delle schede di prodotto.

Esempio di vista parziale :

@model Product
<div class="card">
 <div class="card-body">
 <h5 class="card-title">@Model.Name</h5>
 <p class="card-text">Price: @Model.Price.ToString("C")</p>
 <a asp-action="Details" asp-route-id="@Model.Id" class="btn btn-primary">Details</a>
 </div>
</div>

Includilo in qualsiasi vista con .

Passo 11: Gestione degli errori e codici di stato

I controller dovrebbero gestire con grazia gli errori. Utilizzare blocchi o un gestore di eccezioni globale tramite middleware.

  • per 404]
  • per 400
  • per errori del server.

Puoi anche aggiungere una visualizzazione di errore personalizzata: è già inclusa nel modello. Imposta in []] per reindirizzare le eccezioni in produzione.

Passo 12: Testare l'applicazione MVC

Il test è fondamentale. Utilizzare xUnit e il pacchetto per scrivere test di integrazione. Esempio per l'azione :

public class ProductsControllerTests : IClassFixture<WebApplicationFactory<Program>>
{
 private readonly HttpClient _client;

 public ProductsControllerTests(WebApplicationFactory<Program> factory)
 {
 _client = factory.CreateClient();
 }

 [Fact]
 public async Task Index_ReturnsSuccessAndCorrectContentType()
 {
 var response = await _client.GetAsync("/products");
 response.EnsureSuccessStatusCode();
 Assert.Equal("text/html; charset=utf-8",
 response.Content.Headers.ContentType.ToString());
 }
}

Il controllore di unità prova con servizi ingannevoli per isolare la logica. ASP.NET Core documentazione di prova fornisce esempi estensivi.

Migliori Pratiche e Consigli Avanzati

  • I controller di guardia sono sottili[: La logica aziendale appartiene ai servizi/repositori, non ai metodi di azione.
  • Utilizza modelli di visualizzazione[[[]: Evitare di passare modelli di dominio direttamente alla vista; utilizzare modelli di visualizzazione dedicati per modellare i dati secondo le necessità.
  • Aiutenti di tag di leva[: fanno più pulitore HTML e riducono gli errori nel binding di forma.
  • Abilita la validazione del lato client[]: Include e bundle (già in ).
  • Utilizzare azioni asincroni[[] per operazioni I/O-bound: con .
  • Segui la tua applicazione[[]: Usa sempre HTTPS, token anti-forgery su moduli POST, e autorizzazione basata sul ruolo tramite .

Conclusioni

Implementare l'architettura MVC in ASP.NET Core vi dà una solida base per la costruzione di applicazioni web che sono organizzati, testabili e manutenbili. Separando modelli, viste e controller, è possibile lavorare su ogni componente in modo indipendente e scalare la vostra applicazione con fiducia. I passaggi in questa guida forniscono una completa passeggiata dalla creazione di progetto ai modelli di produzione-ready.