舊版文章以 ASP.NET MVC 5(.NET Framework)為例。本文改以 ASP.NET Core MVC 為例,使用目前的 LTS 版本 .NET 10。MVC 的概念(Model、View、Controller 與 Routing)沿用,專案結構與路由設定的寫法有變動,文末附有新舊對照表。
以前的 Web Forms 強調事件驅動、Page Life Cycle 與一些狀態儲存的觀念,而 MVC 與 Web Forms 的差別可用下面的圖呈現:

Web Forms 的缺點
- 頁面中區分屬於 form 的元素與非 form 的元素
- 肥大的 ViewState 讓傳送網頁過程的資料量比較大
- 控制項一開始是為了節省開發時間而封裝,但也讓開發者對 HTML 的控制不夠直覺
- 不容易撰寫單元測試,也不容易導入 TDD
MVC 帶來的改善
- 關注點分離(SoC, Separation of Concerns):開發人員只需要專注在目前的物件上,不會受到其他物件的干擾或連動影響。
- 易於測試及分工:M、V、C 的職責拆開後,網頁設計人員和前端可以直接參與 View 層的設計。實務上常由同一個人負責 View 與 Model、Controller 的整合,設計原則是 View 愈單純愈好,不將業務邏輯寫在這裡。
- 對 HTTP 輸出有完全的控制權:寫法的風格有點像 Classic ASP。
- 更容易導入 IoC(Inversion of Control)與 DI(Dependency Injection):ASP.NET Core 已內建相依性注入,Controller 的建構函式可以直接注入服務。
從 Web Forms 轉移到 MVC 必須捨棄的特性
- ViewState
- 頁面事件模型(Event Model)
- 封裝的控制項(Server Control)
- 頁面追蹤機制(Page Trace)
其餘 ASP.NET 的特性仍以不同形式保留,在 ASP.NET Core 中的對應如下:
| 舊有特性 | ASP.NET Core 的對應做法 |
|---|---|
| Application Life Cycle | 主機(WebApplication)與中介軟體(Middleware)管線 |
| Web Caching | Output Caching、Response Caching、IMemoryCache |
| Session | Session 中介軟體(AddSession、UseSession) |
| Authentication | Authentication 中介軟體(AddAuthentication、UseAuthentication) |
MVC 職責

- Model(模型):定義資料型態,負責與資料庫溝通、保存程式狀態並執行相應的業務邏輯。常見的做法是以資料庫中某個 Table 的一筆 Record 對應一個 Entity 類別(例如搭配 Entity Framework Core),每個欄位對應一個屬性。
- View(檢視):網頁畫面(HTML,以及一些 JavaScript、CSS),使用 Razor 語法(
.cshtml)。 - Controller(控制器):判斷並請求某個 Model、判斷並導向某個 View。Controller 接受 Routing 分析出的路由,也負責把 Model 的資料傳給 View 輸出。
Web Forms 與 MVC 的網址對應
Web Forms 遵循的是「網址路徑」即「檔案路徑」。以首頁與關於兩個頁面為例:
http://localhost:12081/與http://localhost:12081/Default對應網站根目錄下的/Default.aspx與/Default.aspx.cshttp://localhost:12081/About對應/About.aspx與/About.aspx.cs
MVC 則是透過 Routing 找出對應的 Controller 與 Action,網址不再等於檔案路徑。
建立 ASP.NET Core MVC 專案
使用命令列建立專案(也可以在 Visual Studio 選擇 ASP.NET Core Web App (Model-View-Controller) 範本):
dotnet new mvc -o MyMvcApp
cd MyMvcApp
dotnet run
專案的主要結構如下:
MyMvcApp/
├── Controllers/ Controller 類別
├── Models/ Model 類別
├── Views/ Razor 檢視(.cshtml)
│ ├── Home/ HomeController 對應的檢視
│ └── Shared/ 共用的版面配置(_Layout.cshtml)
├── wwwroot/ 靜態檔案(css、js、圖片)
├── appsettings.json 設定檔
└── Program.cs 應用程式進入點與路由設定
首頁 / 對應的程式位置:
Views/Home/Index.cshtmlControllers/HomeController.cs
Routing 的設定
ASP.NET Core 不再使用 Global.asax.cs 與 RouteConfig.cs,服務註冊與路由都集中在 Program.cs。範本產生的內容類似下面這樣(不同版本的範本可能略有差異,例如較新的範本會改用 MapStaticAssets 提供靜態檔案):
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddControllersWithViews();
var app = builder.Build();
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/Home/Error");
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseAuthorization();
app.MapControllerRoute(
name: "default",
pattern: "{controller=Home}/{action=Index}/{id?}");
app.Run();
各行的作用:
AddControllersWithViews():註冊 MVC(Controller 與 View)所需的服務。UseStaticFiles():提供wwwroot資料夾裡的靜態檔案。UseRouting()與UseAuthorization():啟用路由比對與授權。MapControllerRoute(...):定義預設的傳統路由(conventional routing)。
路由樣式
pattern: "{controller=Home}/{action=Index}/{id?}"
這一句定義網址路徑如何對應到 MVC 的參數,和舊版的差別是預設值直接寫在樣式裡:
{controller=Home}:Controller 的預設值為 Home{action=Index}:Action 的預設值為 Index{id?}:id是選擇性參數,相當於舊版的UrlParameter.Optional
MapControllerRoute 的主要參數:
name:路由名稱pattern:網址路徑要如何對應到 Controller、Action 與路由值,並可內嵌預設值defaults:額外的預設值(選用,多數情況直接寫在pattern內即可)
大括號包起來的名稱是路由變數。{controller} 與 {action} 是核心變數,若網址中沒有提供,就必須有預設值,否則無法對應到 Action。其餘路由變數可以自訂。
舊版的 routes.IgnoreRoute("{resource}.axd/{*pathInfo}") 在 ASP.NET Core 中不再需要,因為已經沒有 .axd 這類的 HttpHandler。
以 About 為例
網址 /Home/About 的對應方式:
{controller}代表 Home{action}代表 About
底層機制會先找到名為 Home 的 Controller(HomeController),再呼叫其中名為 About 的 public 方法(Action,也就是網頁的進入點)。Controller 由相依性注入容器建立,所以建構函式可以直接注入需要的服務。
HomeController.cs 的內容如下(這裡改寫為與舊版相同的三個 Action,範本預設為 Index、Privacy、Error):
using Microsoft.AspNetCore.Mvc;
namespace MyMvcApp.Controllers;
public class HomeController : Controller
{
public IActionResult Index()
{
return View();
}
public IActionResult About()
{
ViewBag.Message = "Your application description page.";
return View();
}
public IActionResult Contact()
{
ViewBag.Message = "Your contact page.";
return View();
}
}
若只輸入預設的網址(例如 https://localhost:埠號/),路由會使用預設值,也就是 Home 這個 Controller 的 Index Action。
在 MVC 專案中,一個 Action 對應一個 View。HomeController 有 Index、About、Contact 三個 Action,各自對應到 Views/Home/ 底下的 Index.cshtml、About.cshtml 與 Contact.cshtml。
屬性路由(Attribute Routing)
除了傳統路由,ASP.NET Core 也可以直接在 Controller 或 Action 上標註路由屬性,這種做法在 REST API 中特別常見:
[Route("products")]
public class ProductsController : Controller
{
[HttpGet("{id:int}")]
public IActionResult Detail(int id)
{
return View();
}
}
上面的 Action 對應網址 /products/5。一般的網頁(Controller 加 View)以傳統路由為主,API 則以屬性路由為主,兩者也可以混用。
新增 View 的常見誤區
新手通常會觀察到 Views 資料夾裡放的是一些前端網頁,並習以為然地直接在裡面新增網頁。在 Visual Studio 中,於 Views/Home 上按右鍵 -> 加入 -> 檢視,選擇 Razor 檢視,輸入名稱 MyWeb。
新增後的 MyWeb.cshtml 可以先寫成下面這樣:
@{
ViewData["Title"] = "MyWeb";
}
<h1>MyWeb</h1>
新增後直接瀏覽 /Home/MyWeb 會得到 404 Not Found。原因是 MVC 設計上不允許直接瀏覽 View(只有 wwwroot 裡的檔案會被當成靜態檔案提供),必須由 Controller 的 Action 來決定要回傳哪一個 View。這裡找不到資源,就是因為 Controller 沒有定義導向 MyWeb 這個 View 的 Action。
在 HomeController 補上下面的 Action 之後,就能正常顯示:
public IActionResult MyWeb()
{
return View();
}
反過來,如果有 Action 但找不到對應的 View 檔案,執行時會出現 InvalidOperationException,訊息會列出搜尋過的路徑。
所以在 MVC 中,一律要先有一個 Controller 的 Action 來主導,才能順利指向 View。
新舊對照:ASP.NET MVC 5 與 ASP.NET Core MVC
| 項目 | ASP.NET MVC 5(.NET Framework) | ASP.NET Core MVC |
|---|---|---|
| 應用程式進入點 | Global.asax.cs 的 Application_Start |
Program.cs |
| 路由設定 | RouteConfig.RegisterRoutes,使用 routes.MapRoute |
app.MapControllerRoute |
| 預設值 | defaults: new { ..., id = UrlParameter.Optional } |
內嵌在樣式中:{controller=Home}/{action=Index}/{id?} |
| 命名空間 | System.Web.Mvc |
Microsoft.AspNetCore.Mvc |
| Action 回傳型別 | ActionResult |
IActionResult(ActionResult 仍可使用) |
| View 副檔名 | .cshtml(Razor) |
.cshtml(Razor) |
| 設定檔 | Web.config |
appsettings.json |
| 相依性注入 | 需要另外整合第三方容器 | 內建 |
| 全域篩選器 | FilterConfig.RegisterGlobalFilters |
在 AddControllersWithViews 的選項中註冊 |
| 打包壓縮 | BundleConfig(System.Web.Optimization) |
沒有對應的內建功能,改用前端建置工具 |
| 靜態檔案 | 專案內的資料夾可直接提供 | 只提供 wwwroot,需啟用 UseStaticFiles |
| 伺服器 | IIS | 內建 Kestrel,可搭配 IIS、Nginx 等 |
ASP.NET MVC 5 沒有直接升級到 ASP.NET Core 的路徑。既有專案可以評估重寫,或使用 System.Web adapters 等工具逐步遷移。