.NET Core Runtime vs .NET Framework Runtime
During my transition period from .NET Framework to .NET Core, one thing really confused me over long period of the time, and that was “runtime”. Runtime has different meaning in .NET Framework and .NET Core.
Runtime for .NET Framework — The History
When someone asks us, what’s .NET Framework runtime, we instantly say CLR (Common Language Runtime), and that is absolutely correct.
This automatically created an impression on our mind that the runtime for .NET Core will be CoreCLR. However that’s true as well, as CoreCLR is the actual runtime that runs the compiled code for .NET Core applications.
But now let’s understand what extra is there in .NET Core runtime apart from CoreCLR.
What’s new in .NET Core Runtime?
Confusion starts when many websites mentions, you have to download ASP.NET Core runtime to run ASP.NET Core application, or install newer runtime to run .NET 6 applications as .NET 6 application will not run on older .NET 5 or .NET Core 3.1 runtimes.
Why so many runtimes?
These things create confusion (if you compare things with .NET Framework) as we never updated runtime in .NET Framework even when were upgrading from 4.5 to 4.6, or 4.6 to 4.7 or 4.8.
So, why does .NET Core ask us to update runtime?
Well, the catch here is the term runtime and it’s different meaning in different context.
- Runtime in .NET Framework was just CLR
- Runtime in .NET Core is not just CoreCLR, but it also includes the .NET Core Base Class Libraries as well.
Starting with .NET Core, Microsoft started communicating that a .NET Core runtime is not just the CLR, but it includes everything that are essential to run a .NET Core application.
So, as per this, a typical .NET Core runtime will include the following:
- CoreCLR — Actual runtime
- .NET Core Base Class Library (CoreFx or .NET Core Framework Libraries)
Once a .NET Core runtime is installed, you can easily run a .NET Core Console application.
Installing only .NET Core runtime doesn’t enable you run an ASP.NET Core web application.
To run an ASP.NET Core web application, you would also need an ASP.NET Core runtime along with existing .NET Core runtime.
ASP.NET Core runtime is a set of framework libraries that builds this ASP.NET Core application framework.
To summarize, following are required to run an ASP.NET Core web app:
- .NET Core runtime (CoreCLR + BCL)
- ASP.NET Core runtime (ASP.NET Core framework libraries)
You can see all the installed runtime from this location: C:\Program Files\dotnet\shared
Hope things are much clear now!
Origin of confusion
All this confusion happened because earlier for .NET Framework, we did not consider BCL (Base Class Libraries) a part of runtime, and just considered CLR as runtime. Ideally, CLR & BCL collectively should have been called as .NET Framework Runtime.
Wrap-up
Thanks for reading! If you liked this, give it some love by pressing on the button! Feel free to comment and highlight.
Name already in use
If nothing happens, download GitHub Desktop and try again.
Launching GitHub Desktop
If nothing happens, download GitHub Desktop and try again.
Launching Xcode
If nothing happens, download Xcode and try again.
Launching Visual Studio Code
Your codespace will open once ready.
There was a problem preparing your codespace, please try again.
Latest commit
Git stats
Files
Failed to load latest commit information.
README.md
This repo contains the code to build the .NET runtime, libraries and shared host ( dotnet ) installers for all supported platforms, as well as the sources to .NET runtime and libraries.
-
(with VS, VS Code, command-line CLI) (Get Started, Tutorials, Porting from .NET Framework, API reference, . )
How can I contribute?
We welcome contributions! Many people all over the world have helped make this project better.
-
explains what kinds of contributions we welcome explains how to build and test explains how to get nightly builds of the runtime and its libraries to test them in your own projects.
Reporting security issues and security bugs
Security issues and bugs should be reported privately, via email, to the Microsoft Security Response Center (MSRC) secure@microsoft.com. You should receive a response within 24 hours. If for some reason you do not, please follow up via email to ensure we received your original message. Further information, including the MSRC PGP key, can be found in the Security TechCenter. You can also find these instructions in this repo’s Security doc.
This repo should contain issues that are tied to the runtime, the class libraries and frameworks, the installation of the dotnet binary (sometimes known as the muxer ) and installation of the .NET runtime and libraries.
For other issues, please file them to their appropriate sibling repos. Their respective links are described in the config issue template doc.
-
/ .NET Framework source index (incl. APIs from daily builds and API usage info) — useful when writing /// comments — a place to discuss the development of .NET and its ecosystem
.NET Runtime is a .NET Foundation project.
There are many .NET related projects on GitHub.
-
— links to 100s of .NET projects, from Microsoft and the community. — the best place to start learning about ASP.NET Core.
This project has adopted the code of conduct defined by the Contributor Covenant to clarify expected behavior in our community. For more information, see the .NET Foundation Code of Conduct.
.NET (including the runtime repo) is licensed under the MIT license.
About
.NET is a cross-platform runtime for cloud, mobile, desktop, and IoT apps.
Understanding .NET Core SDK, Runtime and CLI versioning
In this post I will detail how to install the .NET Core framework and how the SDK and Runtime versions are specified for projects using the CLI and the global.json and .csproj files.
Installing the .NET Core SDK and Runtime
You can find the .NET Core SDK and Runtime downloads for your platform at:
Navigate to the .NET Core version that you want to install, then download the appropriate version of the .NET Core SDK installer for your platform.
For my system I selected the macOS x64 .NET Core SDK installer for version 3.0.100-preview3-010431.
Run the installer to install the .Net Core SDK, Runtime and CLI tools.
.NET Core SDK versions and the CLI
We can use a CLI command to list all installed SDK versions on our system.
Here is a list of the SDK versions installed on my system:
We can see that version 3.0.100-preview3-010431 is the last installed version.
By default the latest installed SDK version will be used by the CLI commands.
I can execute the CLI with the version flag to show the default SDK version that will be used by the CLI tooling on my system:
We can see that version 3.0.100-preview3-010431 is the default SDK version that will be used.
Using the .NET Core CLI to create a new project
Let’s use the CLI to create a new Web API project that will use the default SDK version:
The -o flag specifies a project directory that will be created when we run the command.
We can enter the project directory and check the SDK version:
We can see that the default version 3.0.100-preview3-01043 is being used.
The .NET Core Runtime version and the .csproj file
The runtime version for our project is specified by the demo.csproj file that was generated for the project that we created above.
We can dump the content of the demo.csproj file to inspect the Runtime version being targeted.
The TargetFramework element in demo.csproj file specifies the .NET Core runtime version that we are targeting. In this case, the version that we are targeting is netcoreapp3.0.
You can find more information about target frameworks in the docs at https://docs.microsoft.com/en-us/dotnet/standard/frameworks
Just as we did for the SDK versions, We can list all the installed .NET Core Runtimes on our system using the CLI.
On my system the list looks like this:
Specifying the .NET Core SDK version with global.json
By adding a global.json file to the root directory of our project, we can force the dotnet CLI to use a specific version of the SDK for our project.
The .NET Core documentation at https://docs.microsoft.com/en-us/dotnet/core/tools/global-json gives us the following definition of the global.json file:
The global.json file allows you to define which .NET Core SDK version is used when you run .NET Core CLI commands
When you run a CLI command such as dotnet new or dotnet build , the command will search for a global.json file first in the current directory then all parent directories up to the root directory of the filesystem.
If it can’t find a global.json file, it will default to the newest installed version of the SDK, otherwise it will use the SDK version specified in the first global.json file it encounters.
So by adding a global.json file at the root directory of a project or at the root directory of a solution for multi project solutions, we can specify the exact SDK version that the dotnet CLI commands should use.
As an example let’s use the CLI to create a new global.json file that specifies the .NET Core SDK version 2.2.100 is to be used:
The -o flag specifies that the output directory for the generated global.json file.
We can enter the created directory and dump the content of the global.json file to see that the SDK version 2.2.100 is specified:
We can also check the SDK version using the CLI, from within the demo2 directory, to see that we are now using the specific 2.2.100 version:
Now let’s create a new Web API project inside the directory containing the global.json file:
Note: we didn’t specify an output directory option this time since we are running the dotnet new command within the project directory that was created when we created the global.json file. The dotnet new command will use the current directory name, demo2 , as the .csproj project file name.
We can dump the content of the generated demo2.csproj project file to see the runtime version that we are targeting:
This time we can see that the TargetFramework is set to the netcoreapp2.2 runtime.
Adding a global.json file to an existing project
When we want to add a global.json file to an already existing project we can go into the project directory and run the CLI command to generate the global.json file there, without specifying the output directory option.
As an example I can add a global.json file to the first demo project that we created, like so:
Now we have explicitly locked that project to use version 3.0.100-preview3-010431. The project will continue using version 3.0.100-preview3-010431 even if we later install a newer version of the framework on our system.
If an existing project already contains a global.json file, you can change its .NET Core version, going forward, by changing the framework version specified inside the global.json file.
Recommendations for using global.json files
I have two general recommendations regarding the usage of global.json with any .NET Core project:
Always add a global.json file to your projects to lock the SDK version used by the CLI. This will allow every project to use its own .NET Core version regardless of the default installed SDK version or the versions used in other projects.
Always create a global.json file before using the CLI to generate a new project. This way, the project scaffolding will use the .NET Core version specified in global.json when creating the initial project files.
Here is a sample bash function to automate the process of creating a web api project pinned to specific version of the framework:
If we add this to our shell profile we can create a new web api project for .NET Core version 3 preview 3 by typing dnapi myproj 3.0.100-preview3-010431 .
This will create a new folder named myproj, move into it, add a global.json file with version 3.0.100-preview3-010431 of the framework and then create a new web api project in the directory.
Extending the .Net Core CLI by installing .Net Core Global tools
Global tools are NuGet packages that add features to the .NET Core CLI and are unrelated to the SDK and CLI versioning.
You can add features to the dotnet cli by installing global tools as documented here:
You can find a list of available tools here:
References used for this article
The following articles contain source material that I used as a reference for this article:
Структура и модель выполнения .NET Core приложений
В этой статье я рассмотрю компоненты платформы .NET Core 2.0, необходимые для загрузки и выполнения .NET Core-приложений, а также артефакты для двух возможных типов развертывания.
Текст объемный и рассчитан на:
- начинающих разработчиков, которые только знакомятся с платформой .NET Core;
- опытных разработчиков, выполняющих роль DevOps-инженеров в produсtion-окружении.
Примеры процессов выполнения описаны для ОС Windows, но работают по тому же принципу и на других ОС (с учетом различных расширений исполняемых файлов и нативных библиотек).
0. Pay-for-Play

Каждому .NET-разработчику известно с пелёнок: чтобы запустить любое .NET-приложение, на целевом компьютере должен быть установлен .NET Framework, а именно CLR + BCL.
BCL располагается в GAC, откуда приложения загружают необходимые для работы зависимости.
Архитектура .NET Core в общем виде выглядит так же: .NET Core = Core CLR + Core FX (новое название для BCL), но отличается способом разрешения этих компонентов, а также способом загрузки среды выполнения (CLR). Вместо заголовка в управляемой сборке MyApp.exe в .NET Framework, в .NET Core MyApp.exe сам по себе является нативной программой загрузки Core CLR.
В .NET Core все компоненты программы, которые мы определяем на этапе компиляции, являются зависимостями приложения (включая Core CLR, JIT), которые инфраструктура .NET Core рассматривает как пакеты. Такой пакет называется asset, при этом он может быть как NuGet-пакетом, так и обычным файлом.
Примеры компонентов, которые поставляются через NuGet:
- Microsoft.NETCore.Runtime.CoreCLR — Core CLR.
- Microsoft.NETCore.Jit — JIT-компилятор.
- System.Private.CoreLib — базовые типы System.Object, System.Int32, System.String (аналог mscorlib.dll).
- System.Console — доступ к консоли.
Благодаря такой модели .NET Core-приложение состоит из пугающе огромного количества мелких модулей, но это сделано, чтобы уменьшить объем ненужных зависимостей.
Этот подход называется «pay-for-play»; другими словами, приложения загружают только ту функциональность, которая им необходима, но каждая такая функциональность содержится в отдельной сборке.
1. FDD vs SCD
- Portable (Framework-dependent deployment — FDD)
- Standalone (Self-contained deployment — SCD)
В Standalone (SCD)-приложении все компоненты для выполнения (CoreCLR, CoreFX), а также сторонние библиотеки, то есть абсолютно все зависимости, поставляются вместе с самим приложением (чаще всего в одной папке).
Важно понимать, что Standalone-приложение привязано к определенной ОС и архитектуре (например, Windows 7 x64 или OSX 10.12 x64). Такой идентификатор называется Runtime identifier (RID). Для каждой ОС/архитектуры существует своя версия библиотеки Core CLR (и прочих нативных компонентов), поэтому для Standalone-приложений на этапе компиляции в свойстве RuntimeIdentifier нужно указывать параметры целевой системы (RID).
Такое приложение будет работать на любом компьютере с определенной ОС/архитектурой, независимо от того, установлен ли .NET Core или нет.
2. .NET Core Runtimes (shared frameworks)
Для выполнения Portable-приложений на целевой машине должен быть установлен хотя бы один .NET Core Runtime (shared framework).
.NET Core Runtime устанавливается в папку C:\Program Files\dotnet:

Файлы фреймворка(-ов) хранятся в папке C:\Program Files\dotnet\shared.
Основные составляющие .NET Core Runtime:
- «Утилита» dotnet.exe для запуска .NET Core-приложения. Она называется мультплексор (muxer), и является основным драйвером инфраструктуры .NET Core. Эта программа служит «точкой входа» для запуска любых приложений и выполнения команд разработки. если установлена .NET Core SDK, то есть является хост-процессом любого приложения — corehost.
- Runtime-компоненты (CoreCLR, CoreFX, и т.д.), устанавливаются в отдельную папку фреймворка C:\Program Files\dotnet\shared\[Framework name]\[Framework version].
- Host framework resolver — нативная библиотека, находится в папке
C:\Program Files\dotnet\host\[версия]\hostfxr.dll. При запуске приложения, максимальная версия этой библиотеки выполняет разрешение версии фреймворка для последующего выполнения приложения.
Можно установить несколько версий фреймворка:

Для выполнения Portable-приложения необходимо запустить хост-процесс dotnet.exe и передать ему в качестве аргумента путь к управляемой сборке.
«C:\Program Files\dotnet» добавляется к значению переменной среды PATH, благодаря чему Portable-приложения теперь могут запускаться из командной строки:
В папке приложения (там, где находится [AppName].dll) должен лежать файл [AppName].runtimeconfig.json. В нём указаны имя и версия фреймворка, которые должны быть использованы для выполнения Portable-приложения. Например:
MyApp.runtimeconfig.json
Этот файл является обязательным для Portable-приложений.
Имея вышеприведенную конфигурацию, компоненты среды выполнения будут загружены из папки C:\Program Files\dotnet\shared\Microsoft.NETCore.App\2.0.0.
3. Структура Portable (FDD) .NET Core-приложения
Любое Portable .NET Core-приложение состоит из таких обязательных файлов:
- [AppName].dll — IL-код приложения, точка входа.
- [App dependencies]*.dll — все зависимости приложения, не входящие в состав CoreFX (сборки проектов, сторонние библиотеки, FCL).
- [AppName].runtimeconfig.json — конфигурация среды выполнения, здесь указаны имя и версия .NET Core-фреймворка (runtime-компонентов). Файл является чем-то вроде MyApp.exe.config в .NET Frameowork. Эту конфигурацию можно изменять, если необходимо явно указать конкретный фреймворк.
- [AppName].deps.json — перечень всех зависимостей приложения. Не рекомендуется изменять этот файл, потому что он генерируется при компиляции. Файл не является обязательным, но если его удалить, хост-процесс при запуске не сможет проверить пути всех файлов зависимостей, и выполнение начнется на свой страх и риск.
Артефакты одного и того же Portable-приложения для различных версий платформы .NET Core:

Уменьшение количества файлов объясняется тем, что в Core FX 1.0 отсутствовали многие библиотеки, поэтому они шли в составе приложения, как обычные зависимости. В Core FX 2.0 эти сборки были добавлены, поэтому они больше не поставляются с приложением, а берутся из папки фреймворка.
4. Структура Standalone (SCD) .NET Core приложения
Такая же, как для Portable (FDD)-приложения, но дополнительно содержит все runtime-компоненты (CoreCLR, CoreFX) и собственный мультиплексор dotnet.exe, переименованный в [AppName].exe. Для .NET Core до версии 2.0 мультиплексор для запуска Standalone-приложения идентичен C:\Program Files\dotnet.exe (тот же файл, только переименованный). Для .NET Core 2.0 используется мультиплексор из NuGet-пакета Microsoft.NETCore.DotNetAppHost. В пакете находится один файл apphost.exe, в который при компиляции «зашивается» в имя сборки (MyApp.dll), а сам файл переименовывается в MyApp.exe. При старте Standalone-приложения проверяется «привязка» исполняемого файла (MyApp.exe) к имени сборки, которую он может запустить (MyApp.dll).
Содержимое одного и того же Standalone-приложения для различных версий платформы .NET Core:

Наблюдается картина, противоположная Portable-приложениям — чем больше становится Core FX, тем больше файлов поставляется с приложением.
Рекомендации по выбору типа развертывания
- Всегда отдавайте предпочтение Portable-развертыванию, потому что этот тип гораздо меньше по объему и более стабилен при запуске крупных приложений с большим количеством зависимостей. Кроме того, Portable-приложения легче в настройке, ведь они не зависят от RID.
- Выбирайте Standalone, если нет возможности установить .NET Core Runtime, или если критична продолжительность запуска приложения. В Standalone-версии можно выиграть 1-2 секунды при запуске за счет удаления файла конфигурации [AppName].deps.json (помните, что при этом на вас ложится ответственность за наличие всех файлов зависимостей).
5. Runtime Configuration Files
Файлы [AppName].runtimeconfig.json и [AppName].deps.json называют Runtime Configuration Files (*.deps.json называют dependency manifest file). Они создаются в процессе компиляции и содержат всю информацию, необходимую для запуска dotnet.exe и выполнения приложения.
В [AppName].runtimeconfig.json задаются имя и версия .NET Core runtime (там же указывается, будет ли учтена patch-версия (SemVer) при поиске фреймворка), а также устанавливаются параметры работы Core CLR (режим работы сборщика мусора). Этот файл обязателен для Portable- и не обязателен для Standalone-приложения.
dotnet.exe ([AppName].exe) использует файл [AppName].deps.json для определения абсолютных путей всех зависимостей приложения при его запуске.
Структура [AppName].deps.json:
Термином target называют целевую платформу (имя и версия), на котором должно выполняться данное приложение (напр., .NET Framework 4.6.2, .NET Core App 1.1, Xamarin.Mac 1.0, .NET Standard 1.6). Эта конфигурация аналогична NuGet target framework.
Секция targets определяет платформу и дерево зависимостей для нее в формате
Для выполнения любого приложения, target должен обязательно содержать RID, например .NETCoreApp,Version=v1.1/win10-x64. Файл deps.json Standalone-приложения всегда один и содержит RID целевой платформы. Для Portable-приложения файлов deps.json два — один в папке фреймворка, второй в папке приложения. RID для Portable-приложений указан в файле [FrameworkName].deps.json в папке фреймворка. После того, как dotnet.exe определил фреймворк для выполнения приложения, он сперва загружает deps-файл этого фреймворка (например, C:\Program Files\dotnet\shared\Microsoft.NETCore.App\2.0.0\Microsoft.NETCore.App.deps), а затем deps-файл приложения. Deps-файл приложения имеет более высокий приоритет.
Рассмотрим подробнее содержимое файла deps.json Standalone-приложения:
В свойстве dependencies перечислены зависимости (пакеты) конкретного пакета.
Свойство runtimeTargets используется в deps-файле Portable-приложения и определяет пути файлов библиотек для конкретного RID. Такие RID-specific библиотеки поставляются вместе с Portable-приложением в папке runtimes.
Свойства runtime и native содержат относительные пути управляемых (managed) и нативных библиотек соответственно. Свойство resources содержит относительные пути и локали локализованных сборок-ресурсов.
Пути относительны к NuGet package cache, а не deps-файлу.
Добавить сторонний deps-файл можно передав значение аргумента —additional-deps или переменную среды DOTNET_ADDITIONAL_DEPS.
Такая возможность доступна только для Portable приложений.
Значение аргумента может содержать полный путь к deps-файлу, а также путь к директории, где расположены общие deps-файлы. Внутри этой директории deps-файлы должны быть расположены в структуре \shared\[FX name]\[FX version]\*.deps. Например, shared\Microsoft.NETCore.App\2.0.3\MyAdditional.deps.json.
Когда dotnet.exe (MyApp.exe) определяет пути зависимостей приложения, для каждой отдельной библиотеки составляется список из runtime- и native-путей.
- тип зависимости (project, package, reference),
- serviceable (только для типа package) — индикатор того, является ли пакет Serviceable (определяет, может ли сборка пакета быть пропатчена (заменена) внешними службами, Windows Update или .NET Core Servicing Index).
- хэш пакета (для package зависимостей)
- др. данные
6. Процесс запуска Portable .NET Core-приложения
На целевом компьютере должен быть установлен .NET Core Runtime, соответствующий конфигурации запускаемого приложения.
6.1. Запуск приложения
выполняется при помощи мультплексора (muxer) из командной строки (одинаково на любой ОС).
dotnet.exe — переименованный corehost.exe, эта программа является хост-процессом любого .NET Core-приложения, с неё начинается процесс запуска.
6.2. [corehost] Поиск и загрузка Framework Resolver (hostfxr.dll)
На этом этапе dotnet.exe идет в папку [own directory]/host/fxr/. Для Portable-приложений эта библиотека расположена в общей папке C:\Program Files\dotnet\host\fxr\[FXR version]\hostfxr.dll. Если версий будет несколько, dotnet.exe будет всегда использовать последнюю.
После загрузки hostfxr.dll (Framework Resolver) процесс запуска переходит в рамки этой библиотеки.
6.3. [hostfxr] Определение режима выполнения (standalone, muxer, split/FX)
Первая задача hostfxr — определить режим, в котором будет работать хост процесс и таким образом тип приложения — Portable (FDD) или Standalone (SCD). В Portable (FDD)-режиме он также определяет: это запускаемое приложение или команда SDK.
— если среди аргументов есть такой, значение которого оканчивается на .dll или .exe — процесс запуска продолжится в режиме выполнение указанного файла. Если такого аргумента нет, управление будет передано SDK. Для этого из папки [own directory]\sdk\[version] (если такая существует) будет запущен dotnet.dll (как Portable приложение), и этой сборке будут переданы аргументы текущего хост процесса.
Также для Portable (FDD)-приложения hostfxr определяет фреймворк (.NET Core Runtime), откуда будут загружены компоненты для выполнения.
Алгоритм проверки очень простой — если в папке, откуда был запущен мультиплексор [AppName].exe (в нашем случае dotnet.exe), отсутствует coreclr.dll или [AppName].dll, то приложение Portable. Если один из этих двух файлов существует, то далее идет проверка — приложение Portable (split/FX) или Standalone. Если существует [AppName].dll, то приложение Standalone, иначе — Portable (split/FX).
Запуск Portable-приложения может также осуществляться в так называемом Exec mode.
Для этого команда запуска первым аргументом должна содержать exec C:\> dotnet exec . .
При запуске в таком режиме можно явно указать пути к файлам конфигурации:
—depsfile <PАTH>
—runtimeconfig <PАTH>
которые будут использованы вместо файлов в папке приложения.
6.4. [hostfxr] Определение .NET Core Runtime
Первым делом hostfxr определяет и загружает файлы конфигурации deps и runtimeconfig. Если ничего не переопределено в аргументах, эти файлы берутся из папки приложения.
На текущем этапе hostfxr определяет (по данным файла конфигурации), является ли приложение Portable или Standalone.
После загрузки файлов конфигурации и определения режима hostfxr определяет папку фреймворка (.NET Core Runtime).
Для этого hostfxr сначала определит, какие версии установлены в папке shared, а затем выберет из этого списка релиз-версию, с учетом значений в [AppName].runtimeconfig.json.
При выборе версии учитывается параметр Roll Forward On No Candidate Fx, который указывает строгость соответствия заданной версии и имеющихся на машине.
6.5. [hostfxr] Поиск и загрузка hostpolicy.dll
На текущем этапе всё готово для определения путей runtime-компонентов. Этой задачей занимается библиотека hostpolicy.dll, которая называется Host library.
Процесс поиска hostpolicy.dll заключается в последовательных проверках различных локаций. Но сначала определяется версия hostpolicy из deps-файла фреймворка (напр. C:\Program Files\dotnet\shared\Microsoft.NETCore.App\2.0.0\Microsoft.NETCore.App.deps). В этом файле будет найден пакет с именем Microsoft.NETCore.DotNetHostPolicy и взята его версия.
Затем ищется патч (замена) hostpolicy.dll (с учетом версии, если она была определена на предыдущем шаге, и RID) в папке .NET Core Servicing (для Windows — в папке C:\Program Files[ (x86)]\coreservicing\pkgs). Если такой файл найден, он загружается для дальнейшего использования.
Если файл не был найден на предыдущем этапе, hostpolicy.dll будет найдено в папке фреймворка.
Как только опеределена hostpolicy.dll, hostfxr загружает эту библиотеку и передает ей управление.
6.6. [hostpolicy] Определение списка зависимостей
Библиотека hostpolicy.dll отвечает за определение абсолютных путей всех зависимостей приложения.
Прежде всего hostpolicy создаст компонент под названием Dependencies Resolver, который в свою очередь загрузит два deps-файла — файл фреймворка и файл приложения.
Сперва загружается список из deps-файл фреймворка, где будут определены такие зависимости, как CoreCLR и библиотеки CoreFX. Затем список из deps-файла приложения, в котором указаны сборки нашего приложения и их зависимости.
Для каждого deps-файла Dependency Resolver составляет список всех зависимостей для указанной runtimeTarget.
Для каждого пакета сначала составляется список файлов из всех секций runtimeTargets (RID specific зависимости), далее — список всех файлов из секций native и runtime. Такой объединенный список относительных путей всех зависимостей в условном формате
ID пакета — RID — тип asset’а (runtime, native) — пути к файлам называется Target assets.
После того, как были составлены эти два списка файлов зависимостей (RID и не RID), выполняется процесс под названием Reconciling libraries with targets (согласования). Он заключается в том, что для каждого пакета из секции libraries проверяется, существует ли RID specific-файлы, которые должны переопределить обычные.
6.7. [hostpolicy] Определение путей TPA, Core CLR и CLR Jit
Далее Dependency resolver составляет список абсолютных путей файлов управляемых сборок — зависимостей приложения. Этот список называется TPA (Trusted Platform Assemblies) и передается Core CLR для настройки AppDomain. Также составляется список абсолютных путей директорий, в которых находятся остальных файлы зависимостей (кроме coreclr, corejit).
Определение абсолютных путей управляемых сборок происходит путем поиска файлов в Probe paths (путей зондирования). По умолчанию их два — папка фреймворка и папка приложения, и они основаны на расположении deps-файлов. Также можно добавить дополнительные пути:
1) передав аргумент —additionalprobingpath, например
—additionalprobingpath %UserProfile%\\.nuget\\packages
2) указав в файле [AppName].runtimeconfig.json (приоритет ниже, чем у аргумента), например
В папке фреймворка и приложения наличие файла проверятся (при условии, что он был указан в соответствующем deps-файле) без учета относительного пути, в остальных директориях с учетом относительно пути, потому что эти директории рассматриваются как кеш NuGet-пакета.
- папка приложения;
- папка фреймворка
- Probe paths
После составления списка TPA, определяются пути CoreCLR и CLRJit.
При отсутствии deps-файла приложения, dotnet.exe вначале попытается найти эти библиотеки в [app directory]\lib\. При обычном выполнении пути берутся из папки фреймворка (отбросив относительный путь и взяв только имя файла).
Устанавливаются следующие настройки CoreCLR:
- TRUSTED_PLATFORM_ASSEMBLIES — список обсолютных путей всех управляемых библиотек приложения.
- NATIVE_DLL_SEARCH_DIRECTORIES — абсолютные пути директорий, где найдены нативные зависимости.
- PLATFORM_RESOURCE_ROOTS — абсолютные пути директорий, где найдены зависимости-ресурсы
- AppDomainCompatSwitch — константа «UseLatestBehaviorWhenTFMNotSpecified».
- APP_CONTEXT_BASE_DIRECTORY — папка приложения.
- APP_CONTEXT_DEPS_FILES — абсолютные пути deps-файлов приложения и фреймворка.
- FX_DEPS_FILE — абсолютный путь deps-файла фреймворка.
- PROBING_DIRECTORIES — дополнительные пути зондирования (если они были указаны).
7. Процесс запуска Standalone (SCD) .NET Core приложения
Процесс запуска Standalone-приложения отличается от Portable только начальным этапом, а также местоположением компонентов, которые по умолчанию должны располагаться в папке приложения.
7.1. Запуск приложения
выполняется с помощью запуска собственного мультиплексора MyApp.exe. В .NET Core < 2.0 этот мультиплексор является переименованным общим мультиплексором dotnet.exe. Начиная с .NET Core 2.0 используется отдельный мультиплексор apphost.exe (немного видоизмененная версия dotnet.exe).
Этот файл (apphost.exe) поставляется через NuGet в пакете Microsoft.NETCore.DotNetAppHost.
Внутри файла содержится текстовый placeholder (его значение — SHA-256 хэш строки foobar).
При выполнении команды SDK dotnet build значение placeholder’а меняется на имя запускаемой сборки (напр., MyApp.dll), а apphost.exe переименовывается в MyApp.exe. Таким образом происходит привязка исполняемого файла к сборке. При запуске приложения .NET Core >= 2.0 вначале проверяется эта «привязка».
7.2. Процесс запуска
происходит так же, как у Portable-приложения, за исключением того, что существует только один deps-файл и все зависимости ищутся в папке приложения или по указанным —additionalprobepaths.