上一篇整理完 _Layout.cshtml 之後,我終於知道:
Layout
負責共用外框
View
負責目前頁面內容
@RenderBody()
負責把 View 放進 Layout
但實際看專案時,又會看到另外兩支很容易搞混的檔案:
_ViewStart.cshtml
_ViewImports.cshtml
兩個都有底線。
而且通常都會在 Views 的資料夾階層裡看到。
兩個也都不是一般拿來直接顯示畫面的 View。
所以我一開始真的很容易把它們混在一起。
後來才慢慢整理出來:
_ViewStart.cshtml
比較像是在處理:
「View 開始執行時,要先套哪些共用設定?」
_ViewImports.cshtml
比較像是在處理:
「這些 View 可以共用哪些 Razor 匯入設定?」
這篇就直接用實際專案裡最常見的用法來分。
可以先記:
_ViewStart.cshtml
主要處理 View 執行時的共用設定
_ViewImports.cshtml
主要處理 Razor View 共用的匯入設定
最常看到的內容也完全不一樣。
_ViewStart.cshtml 可能是:
@{
Layout = "_Layout";
}
_ViewImports.cshtml 可能是:
@using MyProject
@using MyProject.ViewModels
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
所以如果只想先快速判斷:
看到 Layout
→ 先想到 _ViewStart.cshtml
看到 @using、@addTagHelper
→ 先想到 _ViewImports.cshtml

_ViewStart.cshtml 到底在做什麼?上一篇有提到,一般 View 可以自己指定 Layout:
@{
Layout = "_Layout";
}
例如:
@{
Layout = "_Layout";
}
<h1>首頁</h1>
這樣當然可以。
但如果專案有很多 View:
Index.cshtml
Create.cshtml
Edit.cshtml
Detail.cshtml
History.cshtml
每一頁都重複寫:
@{
Layout = "_Layout";
}
就很麻煩。
所以通常會把這種共用設定放進:
_ViewStart.cshtml
例如:
@{
Layout = "_Layout";
}
這樣底下很多 View 就不需要每一頁都自己重複指定 Layout。
Views
├── _ViewStart.cshtml
│
├── Home
│ ├── Index.cshtml
│ └── About.cshtml
│
└── Shared
└── _Layout.cshtml
_ViewStart.cshtml:
@{
Layout = "_Layout";
}
Index.cshtml:
<h1>首頁</h1>
About.cshtml:
<h1>關於我們</h1>
雖然這兩支 View 都沒有自己寫:
Layout = "_Layout";
但執行時還是可以套用 _ViewStart.cshtml 裡設定的 Layout。
可以先理解成:
準備執行目前 View
↓
先套用 _ViewStart.cshtml 的設定
↓
取得 Layout
↓
執行目前 View
↓
再和 Layout 組成最後畫面

_ViewStart.cshtml 只是拿來設定 Layout 嗎?不只。
它的概念其實比較接近:
在 View 開始執行時
先跑一段共用 Razor 設定
例如也可能看到:
@{
Layout = "_Layout";
ViewData["SystemName"] = "管理系統";
}
不過實際專案最常見、也最值得先記住的還是:
Layout = "_Layout";
所以初學時,可以先直接把:
_ViewStart.cshtml
↓
預設 Layout
連在一起。
之後遇到更複雜的用法,再慢慢往外擴充就好。
_ViewStart.cshtml 指定的 Layout 嗎?可以。
假設 _ViewStart.cshtml 是:
@{
Layout = "_Layout";
}
代表一般頁面預設使用:
_Layout.cshtml
但登入頁可能不需要 Header、Sidebar,而是想使用另一套版型。
這時 Login.cshtml 可以自己指定:
@{
Layout = "_LoginLayout";
}
例如:
Views
├── _ViewStart.cshtml
│
├── Shared
│ ├── _Layout.cshtml
│ └── _LoginLayout.cshtml
│
└── Account
└── Login.cshtml
_ViewStart.cshtml:
@{
Layout = "_Layout";
}
Login.cshtml:
@{
Layout = "_LoginLayout";
}
<h1>登入</h1>
這時登入頁就會使用:
_LoginLayout.cshtml
所以可以理解成:
_ViewStart.cshtml
提供共用的預設設定
↓
某一支 View
如果有自己的需求
↓
可以再自行指定
_ViewImports.cshtml 又是什麼?這支檔案做的事情就完全不一樣了。
假設 View 裡要使用:
@model UserViewModel
但 UserViewModel 實際上位在:
MyProject.ViewModels
如果 Razor View 沒有匯入這個命名空間,可能就要寫成完整名稱:
@model MyProject.ViewModels.UserViewModel
如果很多 View 都會用到這個 namespace,每一頁都這樣寫會很長。
所以可以在:
_ViewImports.cshtml
統一加入:
@using MyProject.ViewModels
之後 View 就可以直接寫:
@model UserViewModel
不用每一頁都重複寫完整 namespace。
_ViewImports.cshtml 常放什麼?例如:
@using MyProject
@using MyProject.ViewModels
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
初學時可以先分成兩個最常見的東西:
@using
@addTagHelper
@using 是什麼?例如:
@using MyProject.ViewModels
跟一般 C# 裡:
using MyProject.ViewModels;
概念很接近。
目的就是讓 Razor View 可以直接使用這個 namespace 裡面的類別。
例如原本可能要寫:
@model MyProject.ViewModels.UserViewModel
加入:
@using MyProject.ViewModels
之後就可以簡化成:
@model UserViewModel
所以看到:
@model UserViewModel
但目前這支 View 上面完全沒有:
@using MyProject.ViewModels
先不要急著覺得奇怪。
可以去找:
_ViewImports.cshtml
有可能早就在那裡共用匯入了。
@addTagHelper 又是什麼?ASP.NET Core MVC 的 View 裡常會看到:
<form asp-controller="User"
asp-action="Create"
method="post">
</form>
或者:
<input asp-for="Name" />
裡面的:
asp-controller
asp-action
asp-for
不是一般 HTML 原本就有的屬性。
它們是 ASP.NET Core MVC 的 Tag Helper。
而 _ViewImports.cshtml 裡常會看到:
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
可以先理解成:
把 ASP.NET Core MVC 內建的 Tag Helper
提供給這些 Razor View 使用
這樣 View 裡才可以使用像:
asp-for
asp-action
asp-controller
這些 MVC 提供的功能。

_ViewImports.cshtml 是「幫 View 少寫東西」嗎?某種程度上可以先這樣理解。
如果沒有共用匯入,每一支 View 可能都要自己寫:
@using MyProject.ViewModels
@using MyProject.Helpers
有了 _ViewImports.cshtml 之後:
共用的 Razor 匯入設定
↓
集中寫一次
↓
底下很多 View 都可以使用
所以我會把它先記成:
Razor View 的共用匯入區
_ViewStart.cshtml 和 _ViewImports.cshtml 最大差別直接放在一起最好記。
| 檔案 | 主要負責 | 常見內容 |
|---|---|---|
_ViewStart.cshtml |
View 執行時的共用設定 | Layout = "_Layout" |
_ViewImports.cshtml |
Razor View 共用匯入 | @using、@addTagHelper |
我自己會先記成:
_ViewStart
決定 View「開始時要套什麼設定」
_ViewImports
決定 View「可以直接使用什麼」
再具體一點:
_ViewStart.cshtml
↓
這頁預設要套哪個 Layout?
_ViewImports.cshtml
↓
這頁有哪些 namespace、Tag Helper 可以直接使用?
這樣就比較不容易搞混。
不會。
它們都不是像:
Index.cshtml
Create.cshtml
Edit.cshtml
這種主要負責顯示頁面內容的 View。
所以通常不會把真正的頁面內容寫在裡面,例如:
<h1>首頁</h1>
<button>新增</button>
可以先把它們分成:
_ViewStart.cshtml
偏向執行設定
_ViewImports.cshtml
偏向匯入設定
真正的畫面內容,還是在一般 View:
Index.cshtml
Create.cshtml
Edit.cshtml
Detail.cshtml
裡面。
這裡不要看到底線,就以為它們全部都是同一種東西。
例如:
_Layout.cshtml
_ViewStart.cshtml
_ViewImports.cshtml
_Header.cshtml
前面都有 _。
但它們的用途完全不同。
可以整理成:
_Layout.cshtml
↓
Layout
_ViewStart.cshtml
↓
View 執行時的共用設定
_ViewImports.cshtml
↓
Razor 共用匯入設定
_Header.cshtml
↓
可能是 Partial View
所以:
都有底線
不代表功能相同
尤其不能看到 _ 就全部把它們當成 Partial View。
_ViewStart.cshtml 可以放很多層嗎?可以。
這點在比較大的專案裡很容易遇到。
例如:
Views
├── _ViewStart.cshtml
│
└── Admin
├── _ViewStart.cshtml
├── Index.cshtml
└── User.cshtml
外層:
Views/_ViewStart.cshtml
可能設定一般 Layout:
@{
Layout = "_Layout";
}
而 Admin 裡自己的:
Views/Admin/_ViewStart.cshtml
可能再設定:
@{
Layout = "_AdminLayout";
}
所以可以先理解成:
外層 _ViewStart.cshtml
↓
先提供比較大的共用設定
進到內層資料夾
↓
還可以再有自己的 _ViewStart.cshtml
↓
依照該區域的需求調整設定
這也是為什麼實際追企業專案時,如果某個 View 的 Layout 看起來怪怪的,不要只搜尋:
Views/_ViewStart.cshtml
還要看目前 View 所在的資料夾階層裡,有沒有其他 _ViewStart.cshtml。
_ViewImports.cshtml 也有階層概念嗎?有。
例如:
Views
├── _ViewImports.cshtml
│
└── Admin
├── _ViewImports.cshtml
└── Index.cshtml
外層可以放很多 View 都需要的共用匯入。
內層也可以再加入只有這個區域需要的設定。
所以如果某個 View 明明沒有:
@using SomeNamespace
卻還是可以直接使用某個類別,也不要只看目前這支 View。
可以往資料夾階層找:
_ViewImports.cshtml
看看是不是已經在其他地方被共用匯入。
假設今天打開:
Views/User/Edit.cshtml
裡面看到:
@model EditUserViewModel
但我心裡想:
EditUserViewModel 為什麼不用寫完整 namespace?
這時我就會去找:
_ViewImports.cshtml
看看是不是有:
@using MyProject.ViewModels
但如果我的問題變成:
這個 Edit.cshtml 明明沒有寫 Layout
為什麼畫面還是有 Header 和 Sidebar?
這時就會先找:
_ViewStart.cshtml
看看是不是有:
@{
Layout = "_Layout";
}
接著再去:
_Layout.cshtml
找 Header、Sidebar 到底寫在哪裡。
所以我現在的追法會變成:
不知道為什麼會套 Layout?
↓
找 _ViewStart.cshtml
不知道某個類別為什麼可以直接使用?
↓
找 _ViewImports.cshtml
不知道 Header、Sidebar 從哪裡來?
↓
從 _ViewStart.cshtml 找到 Layout
↓
再看 _Layout.cshtml 或 Partial View
這樣追就比一開始看到一堆 .cshtml 到處亂點快很多。
最小範例可以直接這樣。
Views/_ViewStart.cshtml@{
Layout = "_Layout";
}
Views/_ViewImports.cshtml@using MyProject.ViewModels
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
Views/Shared/_Layout.cshtml<!DOCTYPE html>
<html>
<body>
<header>
共用 Header
</header>
<main>
@RenderBody()
</main>
</body>
</html>
Views/Home/Index.cshtml@model HomeViewModel
<h1>@Model.Title</h1>
這時幾支檔案的關係就是:
_ViewStart.cshtml
↓
告訴 Index.cshtml 預設使用哪個 Layout
_ViewImports.cshtml
↓
讓 Index.cshtml 可以直接使用 HomeViewModel
_Layout.cshtml
↓
提供共用頁面外框
Index.cshtml
↓
負責首頁自己的內容
所以這幾支檔案不是互不相關。
而是一起參與 View 最後的產生過程。
_ViewStart.cshtml 和 _ViewImports.cshtml 有一個共同點:
一改
可能同時影響很多 View
例如把:
Layout = "_Layout";
改成:
Layout = "_NewLayout";
可能讓一整群 View 全部換版型。
而如果從 _ViewImports.cshtml 刪掉:
@using MyProject.ViewModels
也可能讓很多 View 同時出現:
找不到型別
找不到 namespace
之類的錯誤。
如果:
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
被移除或改錯,也可能影響很多原本使用:
asp-for
asp-action
asp-controller
的 Razor View。
所以修改前我會先確認:
這支 _ViewStart.cshtml 影響哪些 View?
這支 _ViewImports.cshtml 影響哪些 View?
我真的需要改共用設定嗎?
還是只需要修改目前這一頁?
這跟上一篇修改 _Layout.cshtml 的概念很像。
企業專案裡越共用的檔案,修改前越要先確認影響範圍。
最簡單的記法就是:
_ViewStart.cshtml
↓
View 執行時的共用設定
↓
最常看到 Layout
例如:
@{
Layout = "_Layout";
}
而:
_ViewImports.cshtml
↓
View 共用的 Razor 匯入設定
↓
最常看到 @using 和 @addTagHelper
例如:
@using MyProject.ViewModels
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
所以之後看到:
這個 View 明明沒寫 Layout
為什麼還是有 Header?
先找:
_ViewStart.cshtml
看到:
這個 View 明明沒寫 namespace
為什麼可以直接用 ViewModel?
先找:
_ViewImports.cshtml
整體關係可以整理成:
_ViewStart.cshtml
↓
提供 View 執行時的共用設定
_ViewImports.cshtml
↓
提供 Razor 共用匯入
_Layout.cshtml
↓
提供共用畫面外框
一般 View
↓
負責目前頁面的內容
到這裡,我對 Views 資料夾裡那些一堆底線開頭的 .cshtml,終於不會再全部看成同一種東西。
下一篇接著看另外兩個很容易混在一起的東西:
Partial View 和
RenderSection看起來都像是在把內容拆開,它們實際用途到底差在哪裡?