Razor Page Library:开发独立通用RPL(内嵌wwwroot资源文件夹)
Demo路徑:https://github.com/yanshengjie/RPL.Demo
1. Introduction
Razor Page Library 是ASP.NET Core 2.1引入的新類庫項(xiàng)目,屬于新特性之一,用于創(chuàng)建通用頁面公用類庫。也就意味著可以將多個(gè)Web項(xiàng)目中通用的Web頁面提取出來,封裝成RPL,以進(jìn)行代碼重用。
官方文檔Create reusable UI using the Razor Class Library project in ASP.NET Core中,僅簡(jiǎn)單介紹了如何創(chuàng)建RPL,但要想開發(fā)出一個(gè)獨(dú)立通用的RPL遠(yuǎn)遠(yuǎn)沒有那么簡(jiǎn)單,容我娓娓道來。
2. Hello RPL
老規(guī)矩,從Hello World 開始,我們創(chuàng)建一個(gè)Demo項(xiàng)目。
記住開始之前請(qǐng)確認(rèn)已安裝.NET Core 2.1 SDK!!!
我們這次使用命令行來創(chuàng)建項(xiàng)目:
創(chuàng)建完畢后,雙擊RPL.Demo.sln打開解決方案,如下圖:
修改Page1.cshtml,body內(nèi)添加<h1>This is from CommonUI.Page1</h1>
RPL.Web添加引用項(xiàng)目【RPL.CommonUI】
設(shè)置RPL為啟動(dòng)項(xiàng)目。
CTRL+F5運(yùn)行。
我們觀察到RPL.CommonUI中預(yù)置了一個(gè)Razor Page,因?yàn)镽azor Page是基于文件系統(tǒng)路由,所以直接https://localhost:<port>/myfeature/page1即可訪問。
到這一步,我們就可以篤定RPL正確生效。
3. Keep Going
以上只是簡(jiǎn)單的HTML頁面,如果要想加以潤(rùn)色,就需要寫CSS來處理。
兩種處理方式:
使用內(nèi)聯(lián)樣式
引用外部樣式文件
內(nèi)聯(lián)樣式,很簡(jiǎn)單,就不加以贅述。
我們來定義樣式文件來處理。仿照RPL.Web項(xiàng)目,創(chuàng)建一個(gè)wwwroot根目錄,然后再添加一個(gè)css文件夾,再添加一個(gè)demo.css的樣式文件。
然后將demo.css引用添加到page1.cshtml中。
<head><meta name="viewport" content="width=device-width" /><link rel="stylesheet" href="~/css/demo.css" /><title>Page1</title></head>CTRL+F5重新運(yùn)行,運(yùn)行結(jié)果如下圖:
可以清晰的看到,定義的樣式并未生效。從瀏覽器F12 Developer Tool中可以清晰的看到,無法請(qǐng)求demo.css樣式文件。
到這里,也就拋出了本文所要解決的問題:如何開發(fā)獨(dú)立通用的RPL?
如果RPL中無法引用項(xiàng)目中定義一些靜態(tài)資源文件(CSS、JS、Image等),那RPL將無法有效的組織View。
4. Analyze
要想訪問RPL中的靜態(tài)資源文件,首先我們要弄明白.NET Core Web項(xiàng)目中wwwroot文件夾的資源是如何訪問的。
這一切得從應(yīng)用程序啟動(dòng)說起,為了方便查閱,使用Code Map將相關(guān)代碼顯示如下:
從中可以看出在構(gòu)建WebHost的業(yè)務(wù)邏輯中會(huì)去初始化IHostingEnvironment對(duì)象。該對(duì)象主要用來描述應(yīng)用程序運(yùn)行的web宿主環(huán)境的相關(guān)信息,主要包含以下幾個(gè)屬性:
string EnvironmentName { get; set; }string ApplicationName { get; set; }string WebRootPath { get; set; } IFileProvider WebRootFileProvider { get; set; }string ContentRootPath { get; set; } IFileProvider ContentRootFileProvider { get; set; }從上圖的注釋代碼中可以看到,其初始化邏輯正是去指定WebRootPath和WebRootFileProvider。
如果我們?cè)趹?yīng)用程序未手動(dòng)通過webHostBuilder.UseWebRoot("your web root path");指定自定義的Web Root路徑,那么將會(huì)默認(rèn)指定為wwwroot文件夾。
同時(shí)注意下面這段代碼:
其指定的IFileProvider的類型為PhysicalFileProvider。
到這里,是不是就豁然開朗了,Web 應(yīng)用啟動(dòng)時(shí),指定的WebRootFileProvider僅僅映射了Web應(yīng)用的wwwroot目錄,自然是訪問不了我們RPL項(xiàng)目指定的wwwroot目錄啊。
到這里,其實(shí)我們離問題就很近了。但是只要指定了WebRootFileProvider就可以訪問WebRoot目錄的資源了嗎?并不是。
我們知道,ASP.NET Core是通過由一系列中間件組裝而成的請(qǐng)求管道來處理請(qǐng)求的。不管是View視圖也好,還是靜態(tài)資源文件也好,都是通過Http Request來請(qǐng)求的。HTTP Request流入請(qǐng)求管道后,根據(jù)請(qǐng)求類型,不同的中間件負(fù)責(zé)處理不同的請(qǐng)求。那對(duì)于靜態(tài)資源文件,ASP.NET Core中是借助StaticFileMiddleware中間件來處理的。這也就是為什么在啟動(dòng)類Startup的Configure方法中需要指定app.UseStaticFiles();來啟用StaticFileMiddleware中間件。
在ASP.NET Core 官方文檔中Static files in ASP.NET Core,介紹了如何訪問自定義目錄的靜態(tài)資源文件。
如果需要訪問自定義路徑目錄的資源,需要添加類似以下代碼:
app.UseStaticFiles(new StaticFileOptions{FileProvider = new PhysicalFileProvider(Path.Combine(Directory.GetCurrentDirectory(), "MyStaticFiles")),RequestPath = "/StaticFiles"});但這似乎并不能滿足我們的需求。Why?看標(biāo)題,開發(fā)獨(dú)立通用的RPL。怎么理解獨(dú)立通用?也就意味著RPL中的資源文件最好能夠通過程序集打包。這樣才能完全獨(dú)立。否則,在發(fā)布RPL時(shí),還需要輸出靜態(tài)資源文件,顯然增加了使用的難度。而如何將資源文件打包進(jìn)程序集呢?——內(nèi)嵌資源。
5. Embedded Resource
一個(gè)程序集主要由兩種類型的文件構(gòu)成,它們分別是承載IL代碼的托管模塊文件和編譯時(shí)內(nèi)嵌的資源文件。那在.NET Core中如何定義內(nèi)嵌資源呢?
編輯RPL.CommonUI.csproj文件,添加wwwroot為內(nèi)嵌資源。
?<ItemGroup><EmbeddedResource Include="wwwroot\**\*" /></ItemGroup>添加GenerateEmbeddedFilesManifest節(jié)點(diǎn),指定生成內(nèi)嵌資源清單。
<GenerateEmbeddedFilesManifest>true</GenerateEmbeddedFilesManifest>添加Microsoft.Extensions.FileProviders.EmbeddedNuget包引用。
修改完后的RPL.CommonUI.csproj,如下所示:
<Project Sdk="Microsoft.NET.Sdk.Razor"><PropertyGroup><TargetFramework>netstandard2.0</TargetFramework><GenerateEmbeddedFilesManifest>true</GenerateEmbeddedFilesManifest></PropertyGroup><ItemGroup><PackageReference Include="Microsoft.AspNetCore.Mvc" Version="2.1.0" /><PackageReference Include="Microsoft.Extensions.FileProviders.Embedded" Version="2.1.0" /></ItemGroup><ItemGroup><EmbeddedResource Include="wwwroot\**\*" /></ItemGroup></Project>我們用ildasm.exe反編譯RPL.CommonUI.dll,查看下其程序集清單:
從圖中可以看出內(nèi)嵌的demo.css文件,是以{程序集名稱}.{文件路徑}命名的。
那內(nèi)嵌資源如何訪問呢?可以借助EmbeddedFileProvider,我們仿照上面的例子,在Startup.cs的Configure方法中添加以下代碼:
app.UseStaticFiles();var dllPath = Path.Join(Path.GetDirectoryName(Assembly.GetEntryAssembly().Location), "RPL.CommonUI.dll"); app.UseStaticFiles(new StaticFileOptions {FileProvider = new ManifestEmbeddedFileProvider(Assembly.LoadFrom(dllPath), "wwwroot") });CTRL+F5,運(yùn)行。Perfect!
當(dāng)然這也不是最好的解決方案,因?yàn)槟憧隙ú幌胨姓{(diào)用這個(gè)RPL的地方,添加這么幾句代碼,因?yàn)檫@段代碼有很強(qiáng)的侵入性,且不可隔離變化。
5. Final Solution
編輯RPL.CommonUI.csproj文件,添加wwwroot為內(nèi)嵌資源。
?<ItemGroup><EmbeddedResource Include="wwwroot\**\*" /></ItemGroup>添加GenerateEmbeddedFilesManifest節(jié)點(diǎn),指定生成內(nèi)嵌資源清單。
<GenerateEmbeddedFilesManifest>true</GenerateEmbeddedFilesManifest>添加Microsoft.AspNetCore.StaticFiles和Microsoft.Extensions.FileProviders.EmbeddedNuget包引用。
修改完后的RPL.CommonUI.csproj,如下所示:
<Project Sdk="Microsoft.NET.Sdk.Razor"><PropertyGroup><TargetFramework>netstandard2.0</TargetFramework><GenerateEmbeddedFilesManifest>true</GenerateEmbeddedFilesManifest></PropertyGroup><ItemGroup><PackageReference Include="Microsoft.AspNetCore.Mvc" Version="2.1.0" /><PackageReference Include="Microsoft.AspNetCore.StaticFiles" Version="2.1.0" /><PackageReference Include="Microsoft.Extensions.FileProviders.Embedded" Version="2.1.0" /></ItemGroup><ItemGroup><EmbeddedResource Include="wwwroot\**\*" /></ItemGroup></Project>接下來添加CommonUIConfigureOptions.cs,定義如下:
然后添加CommonUIServiceCollectionExtensions.cs,代碼如下:
修改RPL.Web啟動(dòng)類startup.cs,在services.AddMvc()之前添加services.AddCommonUI();即可。
CTRL+F5重新運(yùn)行,我們發(fā)現(xiàn)H1被成功設(shè)置為紅色,檢查發(fā)現(xiàn)demo.css也能正確被請(qǐng)求,檢查network也可以看到其Request URL為:https://localhost:44379/css/demo.css
Static files in ASP.NET Core
File Providers in ASP.NET Core
ManifestEmbeddedFileProvider Class
Make it easier to use static assets that are part of a RCL project
.NET Core的文件系統(tǒng)[4]:由EmbeddedFileProvider構(gòu)建的內(nèi)嵌(資源)文件系統(tǒng)
相關(guān)文章:?
用ASP.NET Core 2.1 建立規(guī)范的 REST API -- HATEOAS
在ASP.NET Core中使用brotli壓縮
ASP.NET Core2.1 你不得不了解的GDPR
.NET Core 2.1改進(jìn)了性能,并提供了新的部署選項(xiàng)
Entity Framework Core 2.1帶來更好的SQL語句生成方案
原文地址: https://www.cnblogs.com/sheng-jie/p/9165547.html
.NET社區(qū)新聞,深度好文,歡迎訪問公眾號(hào)文章匯總 http://www.csharpkit.com
總結(jié)
以上是生活随笔為你收集整理的Razor Page Library:开发独立通用RPL(内嵌wwwroot资源文件夹)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: CentOS 7.4 下 如何部署 As
- 下一篇: .NET Core微服务之基于Ocelo