1. 程式人生 > >.NET Core的檔案系統[4]:由EmbeddedFileProvider構建的內嵌(資源)檔案系統

.NET Core的檔案系統[4]:由EmbeddedFileProvider構建的內嵌(資源)檔案系統

一個物理檔案可以直接作為資源內嵌到編譯生成的程式集中。藉助於EmbeddedFileProvider,我們可以統一的程式設計方式來讀取內嵌於某個程式集中的資原始檔,不過在這之前我們必須知道如何將一個專案檔案作為資源並嵌入到生成的程式集中。 [ 本文已經同步到《ASP.NET Core框架揭祕》之中]

目錄
一、將專案檔案變成內嵌資源
二、讀取資原始檔
三、EmbededFileProvider

一、將專案檔案變成內嵌資源

在預設情況下,我們新增到一個.NET專案中的靜態檔案並不會成為專案編譯生成的程式集的內嵌資原始檔。如果需要,我們需要通過修改project.json檔案中與編譯相關的設定顯式地將某個專案檔案新增到內嵌資原始檔列表中,這個與內嵌資源相關的配置選項就是“buildOptions/embed

”。“buildOptions/embed”的配置結構比較典型,project.json檔案中涉及到檔案選擇策略的絕大部分配置選項幾乎都採用了這樣的結構。除了用於選在內嵌資原始檔的配置選項“buildOptions/embed”,其他與檔案選擇相關的配置選項還如下這些:

  • buildOptions/compile:從當前專案中選擇參與編譯的原始檔。
  • buildOptions/copyToOutput:從當前專案中選擇在編譯時自動拷貝到輸出目錄(預設為bin目錄)的檔案。
  • packOptions/files:從當前專案中選擇在打包的時候新增到生車的NuGet包的檔案。
  • publishOptions:從當前專案中選擇需要釋出的檔案。

對於包括“buildOptions/embed”在內的上述這五種配置選項,我們可以指定一個物件作為它的值。這個配置物件如下表所示的6個屬性,我們可以利用“include”和“execlude”屬性以Globbing Pattern表示式指定“包含”和“排除”的一組檔案,也可以利用“includeFiles”和“execludeFiles”屬性以檔案路徑(不含萬用字元)的形式將具體指定的檔案“包含進來”或者“排除出去”。這些配置從本質上體現了針對一組專案檔案的“轉移”,在預設的情況原始檔和目標檔案具有完全一致的名稱和相對路徑,如果目標檔案的路徑或者名稱不同,我們可以利用mapping屬性對兩者做一個對映。這些屬性體現的路徑都將專案所在的目錄作為根路徑。

屬性

資料型別

描述

include

string/string[]

以Globbing Pattern表示式形式指定的需要被包含進來的檔案。

execlude

string/string[]

以Globbing Pattern表示式形式指定的需要被排除出去的檔案。它比include屬性具有更高的優先順序,所以如果include和exclude涉及到同一個檔案,該檔案會被排除出去。

includeFiles

string/string[]

以檔案路徑形式指定的需要被包含進來的檔案。它比exclude屬性具有更高的優先順序,所以execlude將某個檔案排除出去,我們可以利用includeFiles屬性將它重新包含進來。

execludeFiles

string/string[]

以檔案路徑形式指定的需要被包含進來的檔案。它的優先順序比上述三個屬性都高,所以include將某個檔案包含進來後,我們可以利用excludeFiles屬性將它重新排除出去。

buildIns

object

這個物件具有include和exclude兩個屬性,表示系統預設提供的檔案。builtIns的include和execlude屬性與上述的同名屬性具有相同的定義方式和作用。如果我們對include和builtIns/include(或者execlude和builtIns/execlude)都做了配置,系統在計算最終選擇的檔案列表時會對它們進行合併。

mappings

map

轉移過程原始檔和目標檔案在路徑佈局上的對映關係,其中Key代表目標檔案的路徑,至於Value,我們可以設定為原始檔的路徑,也可以設定為包含include, exclude,includeFiles and excludeFiles屬性的物件。

接下來我們通過簡單的例項來演示如何在project.json檔案中對“buildOptions/embed”配置選項進行合理的設定從而將我們希望的檔案內嵌到編譯生成的程式集中。我們建立了一個空的.NET Core專案,並按照如下圖所示的結構在根目錄下建立了一個名為“root”的目錄。總的來說該目錄(含其子目錄)一共包含4個文字檔案,我們現在需要通過在project.json檔案中設定它的“buildOptions/embed”配置選項,從而將相應的文字檔案內嵌到專案編譯生成的程式集中。

4

假設我們我們對“buildOptions/embed”配置選項做了如下三種不同的設定。由於include|exclude與builtIns/include|builtIns/exclude具有相同的作用,所以前三種定義方式在檔案選擇的角度上講是完全等效的,最終作為內嵌資源的檔案只有兩個,那就是“root/dir1/foobar/foo.txt” 和“root/dir1/baz.txt”。在預設的情況下,內嵌的資原始檔是根據原始檔在專案中的路徑來命名的,具體的命名規則為“{程式集名稱}.{檔案路徑}”(路徑分隔符替換成“.”),所以這兩個資原始檔的名稱為“App.root.dir1.foobar.foo.txt”與“App.root.dir1.baz.txt”。對於第三種定義方式,我們通過mappings屬性做了一個簡單的路徑對映,進而將兩個資原始檔的名稱改成“foo.txt”和“baz.txt”。

定義1

   1: {  
   2:   ...
   3:   "buildOptions": {
   4:     ...
   5:     "embed": {
   6:       "include"    : "root/**/*.txt",
   7:       "exclude"    : "root/dir1/foobar/*.txt",
   8:       "includeFiles"    : "root/dir1/foobar/foo.txt",
   9:       "excludeFiles"    : "root/dir2/gux.txt"
  10:     }
  11:   }
  12: }

定義2

   1: {  
   2:   ...
   3:   "buildOptions": {
   4:     ...
   5:     "embed": {
   6:       "builtIns": {
   7:         "include": "root/**/*.txt",
   8:         "exclude": "root/dir1/foobar/*.txt"
   9:       },      
  10:       "includeFiles"    : "root/dir1/foobar/foo.txt",
  11:       "excludeFiles"    : "root/dir2/gux.txt"
  12:     }
  13:   }
  14: }

定義3

   1: {  
   2:   ...
   3:   "buildOptions": {
   4:     ...
   5:     "embed": {
   6:       "builtIns": {
   7:         "include": "root/**/*.txt",
   8:         "exclude": "root/dir1/foobar/*.txt"
   9:       },      
  10:       "includeFiles"    : "root/dir1/foobar/foo.txt",
  11:       "excludeFiles"    : "root/dir2/gux.txt"
  12:  
  13:       "mappings": {
  14:         "foo.txt": "root/dir1/foobar/foo.txt",
  15:         "baz.txt": "root/dir1/baz.txt"
  16:       }
  17:     }
  18:   }
  19: }

除了將“buildOptions/embed”配置選項設定為上述這麼一個物件之外,我們還具有一個更加簡單的設定方式,那就是直接設定為一個Globbing Pattern表示式或者表示式陣列。這樣的設定相當於是將設定的Globbing Pattern表示式新增到incude列表中,所以如下所示的兩種配置是完全等效的。

定義1

   1: {  
   2:   ...
   3:   "buildOptions": {
   4:     ...
   5:     "embed": {
   6:       "include" : ["root/**/foo.txt","root/**/bar.txt"]
   7:     }
   8:   }
   9: }

定義2

   1: {  
   2:   ...
   3:   "buildOptions": {
   4:     ...
   5:     "embed" : ["root/**/foo.txt","root/**/bar.txt"]
   6:     }
   7:   }
   8: }

二、讀取資原始檔

每個程式集都有一個清單檔案(Manifest),它的一個重要作用就是記錄組成程式集的所有檔案。總的來說,一個程式集主要由兩種型別的檔案構成,它們分別是承載IL程式碼的託管模組檔案和編譯時內嵌的資原始檔。針對圖4所示的專案結果,如果我們將四個文字檔案以資原始檔的形式內嵌到生成的程式集(App.dll)中,程式集的清單檔案將會採用如下所示的形式來記錄它們。

   1: .mresource public App.root.dir1.baz.txt
   2: {
   3:   // Offset: 0x00000000 Length: 0x0000000C
   4: }
   5: .mresource public App.root.dir1.foobar.bar.txt
   6: {
   7:   // Offset: 0x00000010 Length: 0x0000000C
   8: }
   9: .mresource public App.root.dir1.foobar.foo.txt
  10: {
  11:   // Offset: 0x00000020 Length: 0x0000000C
  12: }
  13: .mresource public App.root.dir2.gux.txt
  14: {
  15:   // Offset: 0x00000030 Length: 0x0000000C
  16: }

表示程式集的Assembly物件定義瞭如下幾個方法來提取內嵌資源的檔案的相關資訊和讀取指定資原始檔的內容。GetManifestResourceNames方法幫助我們獲取記錄在程式集清單檔案中的資原始檔名,而另一個方法GetManifestResourceInfo則獲取指定資原始檔的描述資訊。如果我們需要讀取某個資原始檔的內容,我們可以將資原始檔名稱作為引數呼叫GetManifestResourceStream方法,該方法會返回一個讀取檔案內容的輸出流。

   1: public abstract class Assembly
   2: {   
   3:     public virtual string[] GetManifestResourceNames();
   4:     public virtual ManifestResourceInfo GetManifestResourceInfo(string resourceName);
   5:     public virtual Stream GetManifestResourceStream(string name);
   6: }

三、EmbededFileProvider

在對內嵌於程式集的資原始檔有了大致的瞭解之後,針對與對應的EmbeddedFileProvider的實現原理就很好理解了。雖然編譯之前的原始檔案以目錄的形式進行組織,但是當我們內嵌到程式集之後,目錄結構將不復存在,我們可以理解為所有的資原始檔都儲存在程式集的“根目錄”下。所以在通過 EmbeddedFileProvider構建的檔案系統中並沒有目錄層級的概念,它的FileInfo物件總是對一個具體資原始檔的描述。具體來說,這個藐視資原始檔的FileInfo是如下一個名為EmbeddedResourceFileInfo物件,EmbeddedResourceFileInfo型別定義在NuGet包“Microsoft.Extensions.FileProviders.Embedded”之中。

   1: public class EmbeddedResourceFileInfo : IFileInfo
   2: {
   3:     private readonly Assembly     _assembly;
   4:     private long?             _length;
   5:     private readonly string         _resourcePath;
   6:  
   7:     public EmbeddedResourceFileInfo(Assembly assembly, string resourcePath, string name, DateTimeOffset lastModified)
   8:     {
   9:         _assembly             = assembly;
  10:         _resourcePath         = resourcePath;
  11:         this.Name             = name;
  12:         this.LastModified     = lastModified;
  13:     }
  14:  
  15:     public Stream CreateReadStream()
  16:     {
  17:         Stream stream = _assembly.GetManifestResourceStream(_resourcePath);
  18:         if (!this._length.HasValue)
  19:         {
  20:             this._length = new long?(stream.Length);
            
           

相關推薦

.NET Core檔案系統[4]EmbeddedFileProvider構建資源檔案系統

一個物理檔案可以直接作為資源內嵌到編譯生成的程式集中。藉助於EmbeddedFileProvider,我們可以統一的程式設計方式來讀取內嵌於某個程式集中的資原始檔,不過在這之前我們必須知道如何將一個專案檔案作為資源並嵌入到生成的程式集中。 [ 本文已經同步到《ASP.NET Core框架揭祕》之中] 目錄一

.NET Core檔案系統[3]PhysicalFileProvider構建的物理檔案系統

ASP.NET Core應用中使用得最多的還是具體的物理檔案,比如配置檔案、View檔案以及網頁上的靜態檔案,物理檔案系統的抽象通過PhysicalFileProvider這個FileProvider來實現,該型別定義在NuGet包“Microsoft.Extensions.FileProviders.Phy

Asp.net Core 使用Jenkins + Dockor 實現持續整合、自動化部署部署

前面又是廢話 我之前寫過: Asp.Net Core 程式部署到Linux(centos)生產環境(一):普通部署 Asp.Net Core 程式部署到Linux(centos)生產環境(二):docker部署 大家可能會有疑問,分散式環境當中的部署還是跟我們在windows一樣,一臺機一臺機的去

Asp.net Core 使用Jenkins + Dockor 實現持續整合、自動化部署Jenkins安裝

寫在前面 其實園子裡很多大佬都寫過,我也是一個搬運工很多東西不是原創的,不過還是想把自己安裝的過程,記錄下來如果能幫到大家的忙,也是一件功德無量的事; 執行環境 centos:7.2 cpu:1核 2G記憶體 1M頻寬 其實用的騰訊雲 安裝jenkins 這裡的jenkins就不從docker

c#實戰開發用.net core開發一個簡單的Web以太坊錢包

今天就來開發一個C# 版的簡易錢包 先回顧以前的內容 先看一下視覺化錢包有哪些功能呢? 那這個錢包得有什麼功能呢?  1.檢視使用者 2.檢視交易記錄 3.轉賬 4.釋出智慧合約 5.代幣轉賬 6.代幣查詢 7.實時同步區塊對比 8.智慧填寫手續費 首先新建一個專案 匯入以太坊.net實現類庫

ASP.NET Core Web API下事件驅動型架構的實現一個簡單的實現

很長一段時間以來,我都在思考如何在ASP.NET Core的框架下,實現一套完整的事件驅動型架構

第11章 拾遺4IPv6和IPv4共存技術1_雙棧技術和6to4隧道技術

說明 images 測試結果 ges conf alt style dns服務 數據 6. IPv6和IPv4共存技術 6.1 雙棧技術 (1)雙協議主機的協議結構 (2)雙協議棧示意圖   ①雙協議主機在通信時首先通過支持雙協議的DNS服務器查詢與目的主機名對應的

asp.net core 使用identityServer4的密碼模式來進行身份認證

.sh 錯誤 memory msi entity factory password fig 重載 原文:asp.net core 使用identityServer4的密碼模式來進行身份認證(一)IdentityServer4是ASP.NET Core的一個包含OpenID和

使用 ASP.NET Core MVC 建立 Web API——響應資料的內容協商

使用 ASP.NET Core MVC 建立 Web API 使用 ASP.NET Core MVC 建立 Web API(一) 使用 ASP.NET Core MVC 建立 Web API(二)  使用 ASP.NET Core MVC 建立 Web API(三) 使用 ASP.NET C

基於 abp vNext 和 .NET Core 開發部落格專案 - 部落格介面實戰篇

## 系列文章 1. **[基於 abp vNext 和 .NET Core 開發部落格專案 - 使用 abp cli 搭建專案](https://www.cnblogs.com/meowv/p/12896177.html)** 2. **[基於 abp vNext 和 .NET Core 開發部落格專案

基於 abp vNext 和 .NET Core 開發部落格專案 - 部落格介面實戰篇

## 系列文章 1. **[基於 abp vNext 和 .NET Core 開發部落格專案 - 使用 abp cli 搭建專案](https://www.cnblogs.com/meowv/p/12896177.html)** 2. **[基於 abp vNext 和 .NET Core 開發部落格專案

基於 abp vNext 和 .NET Core 開發部落格專案 - 部落格介面實戰篇

## 系列文章 1. **[基於 abp vNext 和 .NET Core 開發部落格專案 - 使用 abp cli 搭建專案](https://www.cnblogs.com/meowv/p/12896177.html)** 2. **[基於 abp vNext 和 .NET Core 開發部落格專案

基於 abp vNext 和 .NET Core 開發部落格專案 - 部落格介面實戰篇

## 系列文章 1. **[基於 abp vNext 和 .NET Core 開發部落格專案 - 使用 abp cli 搭建專案](https://www.cnblogs.com/meowv/p/12896177.html)** 2. **[基於 abp vNext 和 .NET Core 開發部落格專案

基於 abp vNext 和 .NET Core 開發部落格專案 - 部落格介面實戰篇

## 系列文章 1. **[基於 abp vNext 和 .NET Core 開發部落格專案 - 使用 abp cli 搭建專案](https://www.cnblogs.com/meowv/p/12896177.html)** 2. **[基於 abp vNext 和 .NET Core 開發部落格專案

[ASP.NET Core 3框架揭祕] 檔案系統[4]程式集檔案系統

一個物理檔案可以直接作為資源內嵌到編譯生成的程式集中。藉助於EmbeddedFileProvider,我們可以採用統一的程式設計方式來讀取內嵌的資原始檔,該型別定義在 “Microsoft.Extensions.FileProviders.Embedded”這個NuGet包中。在正式介紹EmbeddedFil

ASP.NET Core 2.0和Angular 4從頭開始構建用於車輛管理的Web應用程式

  目錄 介紹 背景 使用程式碼 I)伺服器端 a)先決條件 b)設定專案 c)設定資料庫 d)使用AutoMapper e)使用Swagger f)執行API II)客戶端 a)先決條件 b)設定專案 c)實現服務 d)

【ASP.NET Core】準備工作在 Windows 10 上配置 Linux 子系統

字符 登錄 界面 div 輸出 ace .... 配置服務 主機 ASP.NET Core 其實比傳統的 ASP.NET 要簡單很多,而且也靈活很多,並且可以跨平臺獨立運行。 在 Windows 平臺上,我們只要在安裝 Visual Studio 的時候選擇跨平臺的 .N

ASP.NET Core 一步步搭建個人網站7_Linux系統移植

window std bce stat 能夠 rpm 設置 with err 摘要 考慮我們為什麽要選擇.NET Core? 因為它面向的是高性能服務器開發,拋卻了 AspNet 的臃腫組件,非常輕量,加上微軟的跨平臺戰略,對 Docker 的親和性,對於開發人員也非常友好

.net core 學習日記二添加swagger支持

star .json .net core 學習 web end direct dds ash swagger 是restful api 文檔生成工具,當加入swagger後,發布api自動生成swagger 頁,記錄對應接口信息,並可在頁面直接測試調取接口。 這篇文章記錄

.Net Core的Log方式Serilog+Kibana

ron href onf exce har json https setting github 前言 Serilog,支持對象,把log數據序列化成Json,好用方便,容易拓展。Github: https://github.com/handsomeyao77/serilog