.Net Core 6 MVC 整合前端 — 2

Conrad
Conrad KU
Published in
14 min readFeb 24, 2023

前言

因為公司內部許多程式都只能用 IE 開啟,但隨著作業系統更新至 Win 10 or Win 11 已經開始不支援 IE 所以要開始著手翻舊系統,而新系統架構選擇用 .Net Core 6 MVC ,藉由這次過程學習 Visual Studio & Resharper & C# & Razor 📖

上一篇:.Net Core 6 MVC 整合前端 — 1

🔖 文章索引

1. 依環境載入 Vue.js
2. 使用 ViewBag 將資料向下傳遞
3. _Layout.cshtml 設定每個頁面獨立加 style & script
4. 各別頁面使用不同 Layout
5. 各別資料夾下的頁面使用同個 Layout
6. 防止 js/css/圖檔舊版 Cache 搗亂
7. Vue Demo
8. Sweet Alert 2 Demo

依環境載入 Vue.js

Vue.js 有分開發版本 ( vue.global.js ) 和上線版本 ( vue.global.prod.js )

當環境是 Production 就要載入上線版本 ( vue.global.prod.js )

@* /Views/Shared/_Layout.cshtml *@

@{
var CurrentEnvironment = Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT");
}

<!DOCTYPE html>
<html lang="en">
<head>
...
</head>
<body>
@RenderBody()

@if( CurrentEnvironment == "Production" )
{
<partial name="_ProdScript" />
}
else
{
<partial name="_DevScript" />
}
</body>
</html>
@* /Views/Shared/_DevScript.cshtml *@

<script src="~/js/chunk-vendors.js"></script>
<script src="~/js/vue.dev.js"></script>
@* /Views/Shared/_ProdScript.cshtml *@

<script src="~/js/chunk-vendors.js"></script>
<script src="~/js/vue.prod.js"></script>

使用 ViewBag 將資料向下傳遞

依照 @{ var CurrentEnvironment = ... } 的宣告方式只能在同一頁面使用這個變數,如果今天想要讓 <partial name="..." /> 頁面內容取得變數就需改用 ViewBag.CurrentEnvironment 的宣告方式

調整 _Layout.cshtml

@* /Views/Shared/_Layout.cshtml *@

@{
// 建議將這段宣告在 /Views/_ViewStart.cshtml
ViewBag.CurrentEnvironment = Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT");
}

<!DOCTYPE html>
<html lang="en">
<head>
@*
5 ways to render a partial view in asp.net core
https://nitishkaushik.com/how-to-render-a-partial-view-in-asp-net-core/
*@
<partial name="_Head" />
@await RenderSectionAsync("AdditionalCSS", required: false)
</head>
<body>
@RenderBody()
<partial name="_Script"/>
@await RenderSectionAsync("AdditionalScript", required: false)
</body>
</html>

_DevScript.cshtml & _ProdScript.cshtml 合併為 _Script.cshtml

@* /Views/Shared/_Script.cshtml *@

<script src="~/js/chunk-vendors.js"></script>

@if (ViewBag.CurrentEnvironment == "Production")
{
<script src="~/js/vue.prod.js"></script>
}
else
{
<script src="~/js/vue.dev.js"></script>
}

Note: @RenderBody() 的頁面 ( EX: /Views/Home/Index.cshtml ) 是吃不到 ViewBag.CurrentEnvironment

但是 /Views/Home/Index.cshtml 上方宣告 @{ ViewBag.Title = "首頁"; } 卻可以讓 /Views/Shared/_Layout.cshtml<partial name="_Head" /> 取得值

要解決讓 /Views/Home/Index.cshtml 也可以吃到 ViewBag.CurrentEnvironment 就要將原本在 /Views/Shared/_Layout.cshtml 的宣告變數在往上移到 /Views/Home/_ViewsStart.cshtml 或者再更往上 /Views/_ViewStart.cshtml

參考:https://dotblogs.com.tw/supershowwei/2020/04/06/090251

_Layout.cshtml 設定每個頁面獨立加 style & script

_Layout.cshtml 加上 RenderSectionAsync(Name, required: false) ,然後 /Views/Home/Index.cshtml 加上 @section Name { ... } ,這樣每個頁面都能添加自己的 <style></style><script></script> 很像寫 Vue SPA,每個 component 都有自己的 <template> & <script> & <style>

@* /Views/Shared/_Layout.cshtml *@

<!DOCTYPE html>
<html lang="en">
<head>
@await RenderSectionAsync("AdditionalCSS", required: false)
</head>
<body>
@RenderBody()
@await RenderSectionAsync("AdditionalScript", required: false)
</body>
</html>
@* /Views/Home/Index.cshtml *@

@{
ViewBag.Title = "首頁";
}

@section AdditionalCSS
{
<style>
body {
color: red;
}
</style>
}

@section AdditionalScript
{
<script>
console.log("Hello World ~");
</script>
}

各別頁面使用不同 Layout

當 URL: /Home/Index 會先看 /Views/_ViewStart.cshtml 設定的 Layout 是哪一個,當然也可以在 /Views/Home/Index.cshtml 最上方宣告要使用哪一個 Layout。

建立兩個 Layout 來做測試,一個 _Layout.cshtml 另一個 _LayoutTest.cshtml ,不同的地方在於 h1 的內容,接著在 /Views/Home/Index.cshtml 最上方宣告使用 Layout = "_LayoutTest"; 就可以囉

@* /Views/Shared/_Layout.cshtml *@

<!DOCTYPE html>
<html lang="en">
<head>
@*
5 ways to render a partial view in asp.net core
https://nitishkaushik.com/how-to-render-a-partial-view-in-asp-net-core/
*@
<partial name="_Head" />
@await RenderSectionAsync("AdditionalCSS", required: false)
</head>
<body>
<h1>_Layout</h1>
@RenderBody()
@await RenderSectionAsync("AdditionalScript", required: false)
</body>
</html>
@* /Views/Shared/_LayoutTest.cshtml *@

<!DOCTYPE html>
<html lang="en">
<head>
@*
5 ways to render a partial view in asp.net core
https://nitishkaushik.com/how-to-render-a-partial-view-in-asp-net-core/
*@
<partial name="_Head" />
@await RenderSectionAsync("AdditionalCSS", required: false)
</head>
<body>
<h1>_Layout Test</h1>
@RenderBody()
@await RenderSectionAsync("AdditionalScript", required: false)
</body>
</html>
@* /Views/Home/Index.cshtml *@

@{
ViewBag.Title = "首頁";
Layout = "_LayoutTest";
}

各別資料夾下的頁面使用同個 Layout

/Views/_ViewStart.cshtml 是設定 /Views 底下所有頁面的 Layout,但是今天我想設定在 /Views/Home 底下頁面的 Layout 就需要在 /Views/Home 底下新增 _ViewStart.cshtml

讀取順序會是 /Views/_ViewStart.cshtml > /Views/Home/_ViewStart.cshtml

防止 js/css/圖檔舊版 Cache 搗亂

<link rel="stylesheet" href="..." /><Script src=".."></script> 加上 asp-append-version="true"

測試結果當內容有改變時會自動 random ?v=xxx

@* /Views/Shared/_Head.cshtml *@

<link rel="stylesheet" asp-append-version="true" href="~/css/chunk-vendors.min.css" />
<link rel="stylesheet" asp-append-version="true" href="~/css/all.min.css" />

@* ============================== *@

@* /Views/Shared/_Script.cshtml *@

<script src="~/js/chunk-vendors.js" asp-append-version="true"></script>

@if (ViewBag.CurrentEnvironment == "Production")
{
<script src="~/js/vue.prod.js" asp-append-version="true"></script>
}
else
{
<script src="~/js/vue.dev.js" asp-append-version="true"></script>
}

Vue Demo

接下來用 Vue 做一個在畫面顯示 Hello Vue ~ 和一個按鈕點下去數字會一直增加。

啟動時可以切換 ProjectName-DevProjectName-Prod 就會發現載入 Vue 的版本不一樣唷

@* /Views/Home/Index.cshtml *@

@{
ViewBag.Title = "首頁";
}

<div id="app">
<div class="container">
<h1>{{ message }}</h1>
<button type="button" class="btn btn-outline-primary" @@click="count++">{{ count }}</button>
</div>
</div>

@section AdditionalScript
{
<script>
const { createApp, ref, onMounted } = Vue;

createApp({
setup() {
const message = "Hello Vue ~";
const count = ref(0);

onMounted(() => {
console.log(`count: ${count.value}`);
});

return {
message,
count
}
}
}).mount('#app');
</script>
}

Sweet Alert 2 Demo

# terminal

$ npm i -S sweetalert2@11.6.8
// bundleconfig.json

[
{
"outputFileName": "wwwroot/js/chunk-vendors.js",
"inputFiles": [
"node_modules/bootstrap/dist/js/bootstrap.bundle.min.js",
"node_modules/sweetalert2/dist/sweetalert2.all.min.js"
]
},
...
]
@* /Views/Home/Index.cshtml *@

@section AdditionalScript
{
<script>
Swal.fire({
title: 'Error!',
text: 'Do you want to continue',
icon: 'error',
confirmButtonText: 'Cool'
});
</script>
}

下一篇:.Net Core 6 MVC 整合前端 — 3

--

--

Conrad
Conrad KU

Remember, happiness is a choice, so choose to be happy.