深入理解.NET Core的基元: deps.json, runtimeconfig.json, dll檔案
原文連結: Deep-dive into .NET Core primitives: deps.json, runtimeconfig.json, and dll's
作者: Nate McMaster
C#編譯器(The C# Compiler)
C#的編譯器可以將cs檔案轉換為dll檔案, 即程式集檔案。程式集檔案是一個便攜的可執行格式檔案, 藉助.NET Core,它可以執行在Windows, MacOS和Linux系統中。
在Windows系統中, .NET Core的編譯器檔案csc.dll存放在以下目錄中
C:\Program Files\dotnet\sdk\[.NET Core 版本號]\Roslyn\bincore
筆者使用了2.1.400版本,所以編譯器存放目錄是C:\Program Files\dotnet\sdk\2.1.400\Roslyn\bincore
.NET Core編譯器檔案csc.dll
也是一個.NET Core應用程式,所以你可以使用dotnet
命令直接執行編譯器
C:\test>dotnet C:\Program Files\dotnet\sdk\2.1.400\Roslyn\bincore\csc.dll --help
下面我們嘗試手動編譯一個cs檔案。
首先我們先建立一個Program.cs
檔案,內容如下:
/* Program.cs */
class Program
{
static void Main(string[] args)
=> System.Console.WriteLine("Hello World!");
}
然後我們使用命令列命令將其編譯
C:\test>dotnet "C:\Program Files\dotnet\sdk\2.1.400\Roslyn\bincore\csc.dll"
-reference:"C:\Program Files\dotnet\sdk\NuGetFallbackFolder\microsoft.netcore.app\2.1.0\ref\netcoreapp2.1\System.Runtime.dll"
-reference:"C:\Program Files\dotnet\sdk\NuGetFallbackFolder\microsoft.netcore.app\2.1.0\ref\netcoreapp2.1\System.Console.dll"
-out:Program.dll
Program.cs
引數說明
"C:\Program Files\dotnet\sdk\2.1.400\Roslyn\bincore\csc.dll"
是編譯器所在的路徑-reference
參數列示編譯中需要引用的dll, 該引數可以指定多個dll , 例子中我們引用了System.Runtime.dll和System.Console.dll-out
參數列示編譯生成的dll路徑Program.cs
表示編譯的原始檔地址
Program.cs
編譯成功, Program.dll
生成完畢。
runtimeconfig.json
對於.NET Core應用程式來說runtimeconfig.json
是不可或缺的。它是用來配置執行時的。
如果缺少了這個檔案,執行dll檔案的時候會產生以下異常。
C:\test>dotnet Program.dll
A fatal error was encountered. The library 'hostpolicy.dll' required to execute the application was not found in '........'
這句話的意思是.NET Core缺少指定元件來執行程式。
為了解決這個問題,我們可以新增一個Program.runtimeconfig.json
, 其內容如下
{
"runtimeOptions": {
"framework": {
"name": "Microsoft.NETCore.App",
"version": "2.1.2"
}
}
}
這裡的配置dotnet命令將使用Microsoft.NETCore.App
作為共享框架(Shared Framework)。當dotnet命令執行的時候,它會去runtimeconfig.json中讀取版本號,然後去C:\Program Files\dotnet\shared\[庫名]\[版本號]
目錄下,搜尋對應的dll檔案
現在我們重新執行上面的命令,結果如下:
C:\test>dotnet Program.dll
Hello world!
Hello World被正確輸出了。
包(Package)
包(Package)是.NET中共享程式碼的一種方式。在.NET中,包的格式是nupkg, nupkg檔案是一個ZIP壓縮檔案, 裡面包含了.NET程式集和一個包含後設資料的xml檔案
。
在.NET中,最著名的包是JSON.NET, 又稱Newtonsoft.Json.它提供了一個JSON序列化和反序列化的API。我們可以從NuGet.org中下載最新版本11.0.2的nupkg檔案,並解壓放置在我們當前的程式碼目錄的packages\Newtownsoft.Json\11.0.2子目錄下。
為了演示如何手動匯入包來編譯專案, 我們修改Program.cs
, 輸出一個序列化之後的物件, 程式碼如下:
class Program
{
static void Main(string[] args)
=> System.Console.WriteLine(
Newtonsoft.Json.JsonConvert.SerializeObject(new { greeting = "Hello World!" }));
}
然後我們使用如下命令,編譯Program.cs
C:\test>dotnet "C:\Program Files\dotnet\sdk\2.1.400\Roslyn\bincore\csc.dll"
-reference:"C:\Program Files\dotnet\sdk\NuGetFallbackFolder\microsoft.netcore.app\2.1.0\ref\netcoreapp2.1\System.Runtime.dll"
-reference:"C:\Program Files\dotnet\sdk\NuGetFallbackFolder\microsoft.netcore.app\2.1.0\ref\netcoreapp2.1\System.Console.dll"
-reference:"C:\Program Files\dotnet\sdk\NuGetFallbackFolder\microsoft.netcore.app\2.1.0\ref\netcoreapp2.1\System.Collections.dll"
-reference:.\packages\Newtonsoft.Json\11.0.2\lib\netstandard1.3\Newtonsoft.Json.dll
-out:Program.dll
Program.cs
這裡為什麼要引入
System.Collections.dll
呢?
原因是我們在程式碼中使用了匿名型別new { greeting = "Hello World!" }
, 對於匿名型別, C#編譯器會為其生成一個.Equals
的方法, 這個方法呼叫了定義在System.Collections.dll
中 的System.Collections.Generic.EqualityComparer
方法
編譯成功,但是會出現一些警告(Warning)
Program.cs(4,35): warning CS1701: Assuming assembly reference 'System.Runtime, Version=4.0.20.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a' used by 'Newtonsoft.Json' matches identity 'System.Runtime, Version=4.2.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a' of 'System.Runtime', you may need to supply runtime policy
這意味著.Newtonsoft.Json的作者建立Newtonsoft.Json.dll
時,是使用4.0.20.0的System.Runtime
程式集, 但是系統當前使用的System.Runtime
程式集是4.2.0.0版本的。編譯器警告你4.0.20.0和4.2.0.0版本可以有很大的差異。不過幸運的是,這些差異都是向後相容的(all backwards comptible), 所以Newtonsoft.Json.dll
可以正常工作。如果想去除這個警告,我們可以使用-nowarn:CS1701
C:\test>dotnet "C:\Program Files\dotnet\sdk\2.1.400\Roslyn\bincore\csc.dll"
-reference:"C:\Program Files\dotnet\sdk\NuGetFallbackFolder\microsoft.netcore.app\2.1.0\ref\netcoreapp2.1\System.Runtime.dll"
-reference:"C:\Program Files\dotnet\sdk\NuGetFallbackFolder\microsoft.netcore.app\2.1.0\ref\netcoreapp2.1\System.Console.dll"
-reference:"C:\Program Files\dotnet\sdk\NuGetFallbackFolder\microsoft.netcore.app\2.1.0\ref\netcoreapp2.1\System.Collections.dll"
-reference:.\packages\Newtonsoft.Json\11.0.2\lib\netstandard1.3\Newtonsoft.Json.dll
-nowarn:CS1701
-out:Program.dll
Program.cs
動態連結(Dynamic Link)
在上一步中,我們編譯了一個引用了Newtonsoft.Json.dll
的.NET Core程式,在引用Newtonsoft.Json.dll
之前,程式碼可以正常執行,但是引用Newtownsoft.Json.dll
之後,程式執行失敗。
C:\test> dotnet Program.dll
Unhandled Exception: System.IO.FileNotFoundException: Could not load file or assembly 'Newtonsoft.Json, Version=10.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed'. The system cannot find the file specified.
.NET是一個動態連結的執行時。編譯器會為Program.dll
程式集新增Newtonsoft.Json.dll
的引用,但是不會複製它的程式碼。.NET Core執行時期望在Program.dll
執行的時候,動態查詢並載入一個Newtonsoft.Json.dll
檔案。這一點對於System.Runtime.dll
, System.Console.dll
以及其他System.*
的程式集也是一樣。
.NET Core可以配置查詢Newtonsoft.Json.dll
檔案的目錄範圍,這裡我們先簡單的將Newtownsoft.Json.dll
拷貝到與Program.dll
相同的目錄中, 然後重新執行Program.dll
C:\test>copy .\packages\Newtonsoft.Json\11.0.2\lib\netstandard1.3\Newtonsoft.Json.dll Newtonsoft.Json.dll
C:\test>dotnet Program.dll
{"greeting":"Hello World!"}
我們預期的結果出現了。
注意:這裡不需要拷貝System.Runtime.dll和System.Console.dll, 原因是他們存在於Microsoft.NETCore.App共享框架中,我們已經在runtimeconfig.json中配置過了。
deps.json
正如上一節所說的.NET Core可以配置查詢動態連結程式集的位置。
這些位置包括:
- 應用程式根目錄(這個不需要配置)
- 包快取目錄
- 優化過的的包快取或者執行時包商店
- 服務索引
- 共享框架(配置在runtimeocnfig.json中)
deps.json
是一個記錄.NET Core中依賴清單的檔案。它可以用來配置動態連結的程式集。
deps.json
檔案中定義了動態連結的依賴列表。通常這個檔案在Visual Studio中是自動生成,而且在生產環境中也會非常的大。但是它確實是一個純文字檔案,所以我們可以使用任何編輯器編寫它。
下面我們手動新增一個Program.deps.json
, 程式碼如下:
{
"runtimeTarget": {
"name": ".NETCoreApp,Version=v2.1"
},
"targets": {
".NETCoreApp,Version=v2.1": {
"Newtonsoft.Json/11.0.2": {
"runtime": {
"lib/netstandard1.3/Newtonsoft.Json.dll": {}
}
}
}
},
"libraries": {
"Newtonsoft.Json/11.0.2": {
"type": "package",
"serviceable": false,
"sha512": ""
}
}
}
現在我們刪除之前拷貝過來的Newtonsoft.Json.dll
, 然後重新執行Program.dll
C:\test>del Newtonsoft.Json.dll
C:\test>dotnet Program.dll
Error:
An assembly specified in the application dependencies manifest (Program.deps.json) was not found:
package: 'Newtonsoft.Json', version: '11.0.2'
path: 'lib/netstandard1.3/Newtonsoft.Json.dll'
由此可見,儘管我們新增了deps.json
, .NET Core依然需要一些其他的資訊來探測deps.json
中定義的動態程式集。
這裡有3種方式來設定,你可以選中一行任意一種方式設定搜尋動態連結庫的目錄路徑,修改之後,{"greeting":"Hello World!"}
就會正常輸出出來。
*.runtimeconfig.dev.json
這種一種方式是最佳的實現方式.我們可以新增一個Program.runtimeconfig.dev.json
,並在其中新增動態連結搜尋目錄欄位additionalProbingPaths
{
"runtimeOptions": {
"additionalProbingPaths": [
"/Users/nmcmaster/code/packages/"
]
}
}
註解:這裡的配置類似於Transformed Config, 如果指定當前的環境是dev,它就會讀取Program.runtimeconfig.json, 並將Program.runtimeconfig.dev.json的內容覆蓋進去
命令列
我們還是可以使用dotnet exec
命令並指定--additionalprobingpath
引數來配置檢索的目錄。
C:\test> dotnet exec --additionalprobingpath ./packages/ Program.dll
*.runtimeconfig.json
當然你也可以直接在*.runtimeconfig.json
中新增additionalProbingPaths
欄位
{
"runtimeOptions": {
"framework": {
"name": "Microsoft.NETCore.App",
"version": "2.1.2"
},
"additionalProbingPaths": [
"./packages/"
]
}
}
相關文章
- 理解ASP.NET Core - 檔案伺服器(File Server)ASP.NET伺服器Server
- .NET Core 3.0之深入原始碼理解HttpClientFactory(二)原始碼HTTPclient
- .NET Core 3.0之深入原始碼理解HttpClientFactory(一)原始碼HTTPclient
- 深入理解Aspnet Core之Identity(4)IDE
- .net core使用配置檔案
- ASP.NET Core - .NET 6 的入口檔案ASP.NET
- ASP.NET Core 配置檔案ASP.NET
- ASP.NET Core - 入口檔案ASP.NET
- .NET Core常用配置檔案示例
- Reactor:深入理解reactor coreReact
- 深入理解JVM類檔案格式JVM
- 深入理解檔案許可權
- .NET Core 3.0之深入原始碼理解Configuration(二)原始碼
- .NET Core 3.0之深入原始碼理解Configuration(三)原始碼
- .NET Core 3.0之深入原始碼理解Kestrel的整合與應用(二)原始碼
- .NET Core 3.0之深入原始碼理解Kestrel的整合與應用(一)原始碼
- .Net Core中的配置檔案原始碼解析原始碼
- 如何編制微軟.Net Core的docker檔案?微軟Docker
- ASP.NET Core 檔案上傳ASP.NET
- 深入淺出Dotnet Core的專案結構變化
- [深入理解Redis]讀取RDB檔案Redis
- 深入理解 webpack 檔案打包機制Web
- .net core 靈活讀取配置檔案
- asp .net core 靜態檔案資源
- .NET Core 6.0之讀取配置檔案
- .net core 獲取檔案MIME型別型別
- .Net引用根目錄子資料夾下的dll檔案
- asp.net網頁中呼叫c#寫的dll檔案ASP.NET網頁C#
- .net core遷移實踐:專案檔案csproj的轉換
- 批處理檔案(bat檔案)註冊dll批量註冊dllBAT
- 深入理解JVM(五)Class類的檔案結構JVM
- 破解class檔案的第一步:深入理解JAVA Class檔案Java
- Net.Core匯入EXCel檔案裡的資料Excel
- .NET CORE 2.1 匯出excel檔案的兩種方法Excel
- 深入理解 Laravel 中.env 檔案讀取Laravel
- Asp.Net Core入門之配置檔案ASP.NET
- asp.net core 系列之靜態檔案ASP.NET
- [譯]ASP.NET Core 2.0 本地檔案操作ASP.NET