【asp.net core 系列】5 布局頁和靜態資源

0. 前言

在之前的4篇的內容里,我們較為詳細的介紹了路由以及控制器還有視圖之間的關係。也就是說,系統如何從用戶的HTTP請求解析到控制器里,然後在控制器里處理數據,並返回給視圖,在視圖中显示出來。這一篇我將為大家介紹基礎的最後一部分,布局頁和靜態資源引入。

1. 布局頁

在控制器和視圖那一篇,我們了解到_ViewStart 里設置了一個Layout屬性的值,這個值正是用來設置布局頁的。所謂的布局頁,就是視圖的公用代碼。在實際開發中,布局頁通常存放我們為整個系統定義的頁面框架,視圖裡寫每個視圖的頁面。

回顧一下,默認的_ViewStart里的內容是:

@{
    Layout = "_Layout";
}

默認的布局頁指定的是名為_Layout的布局頁,在本系列第三篇中,我們得知這個視圖應當在Shared文件夾下,那我們進去看一下這個視圖有什麼內容:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>@ViewData["Title"] - MvcWeb</title>
    <link rel="stylesheet" href="~/lib/bootstrap/dist/css/bootstrap.min.css" />
    <link rel="stylesheet" href="~/css/site.css" />
</head>
<body>
    <header>
        <nav class="navbar navbar-expand-sm navbar-toggleable-sm navbar-light bg-white border-bottom box-shadow mb-3">
            <div class="container">
                <a class="navbar-brand" asp-area="" asp-controller="Home" asp-action="Index">MvcWeb</a>
                <button class="navbar-toggler" type="button" data-toggle="collapse" data-target=".navbar-collapse" aria-controls="navbarSupportedContent"
                        aria-expanded="false" aria-label="Toggle navigation">
                    <span class="navbar-toggler-icon"></span>
                </button>
                <div class="navbar-collapse collapse d-sm-inline-flex flex-sm-row-reverse">
                    <ul class="navbar-nav flex-grow-1">
                        <li class="nav-item">
                            <a class="nav-link text-dark" asp-area="" asp-controller="Home" asp-action="Index">Home</a>
                        </li>
                        <li class="nav-item">
                            <a class="nav-link text-dark" asp-area="" asp-controller="Home" asp-action="Privacy">Privacy</a>
                        </li>
                    </ul>
                </div>
            </div>
        </nav>
    </header>
    <div class="container">
        <main role="main" class="pb-3">
            @RenderBody()
        </main>
    </div>

    <footer class="border-top footer text-muted">
        <div class="container">
            &copy; 2020 - MvcWeb - <a asp-area="" asp-controller="Home" asp-action="Privacy">Privacy</a>
        </div>
    </footer>
    <script src="~/lib/jquery/dist/jquery.min.js"></script>
    <script src="~/lib/bootstrap/dist/js/bootstrap.bundle.min.js"></script>
    <script src="~/js/site.js" asp-append-version="true"></script>
    @RenderSection("Scripts", required: false)
</body>
</html>

這是默認的布局頁內容,看着挺多的,但是除了一些html代碼,裏面還有一些關鍵的地方需要注意。

1.1 RenderSection

RenderSection 分部渲染,在頁面中創建一個標記,表示這個頁面塊將在子視圖(或者是路由的實際渲染視圖)中添加內容。

來,我們看一下微軟官方給的註釋:

In layout pages, renders the content of the section named name.

意思就是在布局頁中,渲染名稱為name的分部內容。

新創建一個分佈頁,名稱為_Layout1

<html>
    <head>
        <title>Render 測試</title>
    </head>
    <body>
        @RenderSection("SectionDemo")
    </body>
</html>

這個布局頁里什麼都沒有,只有一個RenderSection。現在我們新建一個控制器:

using Microsoft.AspNetCore.Mvc;

namespace MvcWeb.Controllers
{
    public class RenderTestController : Controller
    {
        public IActionResult Index()
        {
            return View();
        }
    }
}

創建對應的視圖:

Views / RenderTest/Index.cshtml

先設置布局頁為_Layout1

@{
    Layout = "_Layout1";
}

先試試啟動應用,訪問:

http://localhost:5006/RenderTest/Index

正常情況下,你應該能看到這個頁面:

仔細看一下信息,意思是在 RenderTest/Index.cshtml 視圖中沒有找到 SectionDemo 的分部內容。

那麼,如何在視圖中設置分部內容呢?

@{
    Layout = "_Layout1";
}
@section SectionDemo{
    <h1>你好</h1>

}

使用 @section <Section 名稱> 後面跟一對大括號,在大括號中間的內容就是這個section(分部)的內容。

重啟應用,然後刷新頁面,你能看到這樣的頁面:

如果不做特殊要求的話,定義在布局頁中的分部塊,視圖必須實現。當然,RenderSection還有一個參數,可以用來設置分部不是必須的:

public HtmlString RenderSection(string name, bool required);

1.2 RenderBody

先看下微軟給的官方註釋:

In a Razor layout page, renders the portion of a content page that is not within a named section.

簡單講,如果在布局頁中設置了@RenderBody,那麼在使用了這個布局頁的視圖裡所有沒被分部塊包裹的代碼都會渲染到布局頁中聲明了@RenderBody的地方。

修改_Layout1.cshtml:

<html>
    <head>
        <title>Render 測試</title>
    </head>
    <body>
        <h1>RenderBody 測試 -之前</h1>
        @RenderBody()
        <h1>RenderBody 測試 -之後</h1>
    </body>
</html>

修改RenderTest/Index.cshtml

@{
    Layout = "_Layout1";
}

RenderBody測試
<h1>我是視圖的內容!</h1>

重啟應用,刷新剛剛訪問的頁面:

可以看出,RenderBody渲染的位置。

2. 靜態資源引入

通常情況下,靜態資源的引入與HTML引用js和css等資源是一致的,但是對於我們在編寫系統時自己創建的腳本和樣式表,asp.net core提供了不同的處理方式。那就是服務器端壓縮功能。

asp.net core 3.0 的mvc 默認項目是不啟動這個功能的,需要我們額外的開啟支持。

2.1 開啟支持

先引入 BuildBundleMinifier

cd MvcWeb # 切換目錄到MvcWeb項目下
dotnet add package BuildBundleMinifier

創建 bundleconfig.json

[
    {
        "outputFileName": "wwwroot/css/site.min.css",
        "inputFiles": [
            "wwwroot/css/site.css"
        ]
    },
  	{
        "outputFileName": "wwwroot/js/site.min.js",
        "inputFiles": [
          "wwwroot/js/site.js"
        ],
        "minify": {
          "enabled": true,
          "renameLocals": true
        },
        "sourceMap": false
      }
]

每個節點允許設置項:

  • outputFileName 生成的捆綁壓縮文件,通常路徑攜帶wwwroot
  • inputFiles 數組,包含要壓縮到此次輸出文件的文件路徑,會按照添加的順序依次加入
  • minify 輸出類型的縮小選項,可選。 默認是 enabled: true
  • sourceMap 表示是否為捆綁的文件生成源映射的標記
  • sourceMapRootPath 源映射文件的路徑

2.2 使用

正常情況下在布局頁中,把壓縮后的文件路徑引入即可。不過在開發中,通常按照以下方式引用:

<environment exclude="Development">
    <link rel="stylesheet" href="~/css/site.min.css" asp-append-version="true" />
</environment>
<environment include="Development">
    <link rel="stylesheet" href="~/css/site.css" />
</environment>

注: asp-append-version 表示在引用路徑追加一個版本號,這是針對html靜態資源緩存的問題的一個解決方案,這一步是由程序決定的。

environment表示環境,現在大家知道這個寫法就行,在接下來的篇幅會講。

3. 靜態資源目錄

我們知道到目前為止,我們的靜態資源都是在wwwroot目錄下。那麼我們是否可以修改或者添加別的目錄作為靜態資源目錄呢?

在Startup.cs文件內的Configure方法下有這樣一行代碼:

app.UseStaticFiles();

這行代碼的意思就是啟用靜態文件,程序自動從 wwwroot尋找資源。那麼,我們就可以從這個方法入手,設置我們自己的靜態資源:

public static IApplicationBuilder UseStaticFiles(this IApplicationBuilder app, StaticFileOptions options);

我們找到了這個方法的另一個重載版本,裏面有一個參數類:

public class StaticFileOptions : SharedOptionsBase
{
    public StaticFileOptions();
    public StaticFileOptions(SharedOptions sharedOptions);
    public IContentTypeProvider ContentTypeProvider { get; set; }
    public string DefaultContentType { get; set; }
    public HttpsCompressionMode HttpsCompression { get; set; }
    public Action<StaticFileResponseContext> OnPrepareResponse { get; set; }
    public bool ServeUnknownFileTypes { get; set; }
}

並沒有發現我們想要的,先別慌,它還有個父類。我們再去它的父類里看看:

public abstract class SharedOptionsBase
{
    protected SharedOptionsBase(SharedOptions sharedOptions);
    public IFileProvider FileProvider { get; set; }
    public PathString RequestPath { get; set; }
    protected SharedOptions SharedOptions { get; }
}

這下就比較明了了,需要我們提供一個文件提供器,那麼我們來找一個合適的IFileProvider實現類吧:

public class PhysicalFileProvider : IFileProvider, IDisposable

這個類可以滿足我們的要求,它位於命名空間:

namespace Microsoft.Extensions.FileProviders

那麼,添加一組我們自己的配置吧:

using Microsoft.Extensions.FileProviders;

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
    // 省略其他代碼,僅添加以下代碼
    app.UseStaticFiles(new StaticFileOptions
    {
        FileProvider = new PhysicalFileProvider(Path.Combine(Directory.GetCurrentDirectory(),"OtherStatic")),
    });
}

在項目的根目錄創建名為OtherStatic的文件夾,然後在裏面創建個文件夾,例如: files,並在這個文件夾里隨便添加一個文件。

然後啟動應用訪問:

http://localhost:5006/files/<你添加的文件(包括後綴名)>

然後能在瀏覽器中看到這個文件被正確響應。

當然,這裏存在一個問題,如果在 OtherStatic中的文件在wwwroot也有相同目錄結構的文件存在,這樣訪問就會出現問題。這時候,可以為我們新加的這個配置設置一個請求前綴:

app.UseStaticFiles(new StaticFileOptions
{
    FileProvider = new PhysicalFileProvider(Path.Combine(Directory.GetCurrentDirectory(),"OtherStatic")),
    RequestPath = "/other"
});

重啟程序,然後訪問:

http://localhost:5006/other/files/<你添加的文件(包括後綴名)>

然後就能看到剛才響應的文件,重新訪問之前的路徑,發現瀏覽器提示404。

4. 總結

在這一篇,我們講解了布局頁的內容,靜態資源的壓縮綁定以及添加一個新的靜態資源目錄。通過這幾篇內容,讓我們對asp.net core mvc有了一個基本的認知。下一篇,我們將重新創建一個項目,並結合之前的內容,以實戰為背景,帶領大家完成一個功能完備的web系統。

更多內容煩請關注我的博客《高先生小屋》

本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

※自行創業缺乏曝光? 網頁設計幫您第一時間規劃公司的形象門面

※如何讓商品強力曝光呢? 網頁設計公司幫您建置最吸引人的網站,提高曝光率!

※綠能、環保無空污,成為電動車最新代名詞,目前市場使用率逐漸普及化

※廣告預算用在刀口上,台北網頁設計公司幫您達到更多曝光效益

※教你寫出一流的銷售文案?

※別再煩惱如何寫文案,掌握八大原則!

您可能也會喜歡…