.NET Core depth understanding of primitives (II) - sharing framework

Original: Deep-dive into .NET Core primitives , part 2: the shared framework
Author: Nate McMaster
translation: in-depth understanding of .NET Core primitives (b) - shared framework
of: Lamond Lu

Benpian before translated " in-depth understanding of primitive .NET Core: deps.json, runtimeconfig.json, dll file ," the follow-up, this series of temporary only wrote three, although there are some content and .NET Core 3.0 no longer compatible, but also most of the principles are the same, so I will back the third in translation.

Foreword

Since .NET Core 1.0 onwards, sharing framework (Shared Framework) has become an important part of .NET Core. Since .NET Core 2.1 onwards, ASP.NET Core had first appeared as a shared framework. You may have never noticed this, but the design of it, we went through a lot of repetitive and ongoing discussions. In this article, we'll delve into the shared framework and discuss some of the pitfalls often encountered some developers.

Fundamentals

.NET Core applications may be run in two modes, each mode is dependent on the frame (Framework - Dependent) and standalone mode (Self Contained). On my Macbook, a minimum of independently run ASP.NET Core web applications, has about 350 documents, a total file size is 93MB. In contrast, a minimal dependence application framework, about 5 files, total size 239KB.

You can use the following command line is generated based on two different modes.

dotnet new web
dotnet publish --runtime osx-x64 --output bin/self_contained_app/
dotnet publish --output bin/framework_dependent_app/

When the program runs, and their function is the same. So what is the difference between these two models have it? In fact, as explained in the document's official website:

Deployment dependent frame (framework-dependant deployment) dependent .NET Core target shared components installed. Independent deployed (self-contained deployment) does not depend on the target shared components installed in the system, all the components required for the program have been included in the current application.

This official document ( https://docs.microsoft.com/en-us/dotnet/core/deploying/ ) in a very good explanation of the advantages of the different modes.

PS: On the side was written article, without introducing Framework-dependent executables (FDE), interested students can see themselves.

Sharing framework

Here, simply put, .NET Core Framework is a shared assembly (* .dll files) directory collection, these assemblies do not need to appear in your .NET Core application directory. This directory is part of a shared system-wide version of .NET Core, usually you can C:\Program Filres\dotnet\sharedfind it in.

When you run the dotnet.exe WebApi1.dllcommand, .NET Core host program

  • Try to find your applications rely assembly name and version
  • In some try to find a fixed position in the assembly

These assemblies can be found in many different positions, comprising a frame is not limited to sharing. In my previous article, I explained that if by major deps.jsonand runtimeconfig.jsonbehavioral profiling host program. Students want to know more, you can view the article.

.NET Core host program reads the *.runtimeconfig.jsonfile to determine which version of load sharing framework. Contents of this file like this:

{
  "runtimeOptions": {
    "framework": {
      "name": "Microsoft.AspNetCore.App",
      "version": "2.1.1"
    }
  }
}

Here, the name is just a name shared framework. By convention, the name should be based on .Appthe end, but in fact it can be any string, such as "FooBananaShark".

For version shared framework, here it is configured with a minimum version. .NET Core host program based on the configuration, the corresponding version of the shared loading frame, or shared frame later, but it will never be lower than the specified version of the load sharing framework.

So, in the end what I shared framework installed it?

Run dotnet --list-runtimes, you can see which shared framework installed on your computer, as well as their version and file location.

Contrast Microsoft.NETCore.App, AspNetCore.AppandAspNetCore.All

Here, .NET Core 2.2, for example.

Frame names description
Microsoft.NETCore.App Run-time basis. It mainly offers System.Object, List<T>, stringclass, and memory management, file management, network I / O, thread management and other functions
Microsoft.AspNetCore.App The default Web runtime. It mainly provides the use of API functions to create a Web server, where the main part of the function included Kestral, Mvc, SignalR, Razor, and EF Core of.
Microsoft.AspNetCore.All Integration with third-party libraries. It added EF Core + Sqlite support, as well as a number of extensions, such as Redis, Azure Key Valut and so on. (No longer used in the .NET Core 3.0)

Relationship sharing framework and package Nuget

.NET Core SDK generated runtimeconfig.jsonfile. In .NET Core 1 and 2, SDK project configuration using two section determines runtimeconfig.jsonthe file part of the frame.

  • MicrosoftNETPlatformLibraryAttributes. For all .NET Core project, which by default Microsoft.NETCore.App.
  • Restore result set Nuget package management tool, the result set may contain a package with the same name

Here for all .NET Core project, .NET Core SDK will add an implicit reference to the package Microsoft.NETCore.App. ASP.NET Core by modifying the default configuration MicrosoftNETPlatformLibrary, change it Microsoft.AspNetCore.App.

It should be noted, however, Nuget package management tools do not provide any framework for sharing! Does not provide any framework for sharing! Does not provide any framework for sharing! Important things to say three times ^ _ ^. Nuget package management tools provide only some of the API used by the compiler, and a small SDK. Get source can be shared framework runtime installer https://aka.ms/dotnet-download , or bundled in Visual Studio, Docker mirror, as well as some of the Azure server.

Version before rolling strategy

As I mentioned above, runtimeconfig.jsonbut specifies a minimum version. The actual release will depend on the use of race strategy the previous version (details can be found in the official documentation . For example

  • If the minimum version of the application using a shared framework 2.1.0, the version of the framework program will load the highest share is 2.1. *.

For this part, you can see "in-depth understanding of .NET Core primitives (III): in-depth understanding runtimeconfig.json"

Author: "in-depth understanding of .NET Core primitives (III): in-depth understanding runtimeconfig.json" will follow up on

Share layered framework

The introduction of the shared characteristics of hierarchical framework in .NET Core 2.1 release.

Sharing framework may depend on other shared framework. This feature is incorporated to support ASP.NET Core, this feature can be run when the package is converted to a shared memory frame.

If you look at $DOTNET_ROOT/shared/Microsoft.AspNetCore.All/$version/the folder, you'll find a file called Microsoft.AspNetCore.All.runtimeconfig.jsonfile, which reads as follows

$ cat /usr/local/share/dotnet/shared/Microsoft.AspNetCore.All/2.1.2/Microsoft.AspNetCore.All.runtimeconfig.json
{
  "runtimeOptions": {
    "tfm": "netcoreapp2.1",
    "framework": {
      "name": "Microsoft.AspNetCore.App",
      "version": "2.1.2"
    }
  }
}

Multi-level retrieval

The introduction of multi-stage retrieval characteristics of .NET Core 2.0.

Host program will start probing at a plurality of positions, to find a suitable sharing framework. Dotnet first looks for the root directory that contains a dotnet.exedirectory of the executable file. Here we can configure DOTNET_ROOToverride this configuration environment variable. According to this configuration, the first directory to retrieve are:

$DOTNET_ROOT/shared/$name/$version

If this directory does not exist, the host program tries to use a multi-stage retrieval mechanism of retrieving the predetermined path of the global list. This mechanism can be by setting a global variable DOTNET_MULTILEVEL_LOOKUP=0to shut down. By default, a predetermined global path list is as follows:

THE Location
Windows C:\Program Files\dotnet(Process 64) C:\Program Files (x86)\dotnet(Process 32) ( View Source )
macOS /usr/local/share/dotnet( View source )
Unix /usr/share/dotnet( View source )

The final host program retrieves the following directory in the global directory to find the

$GLOBAL_DOTNET_ROOT/shared/$name/$version

ReadyToRun properties

Assembly shared framework, it is to undergo a crossgentool pre-optimized. Using this tool can generate "ReadyToRun" version of the assembly, these assemblies are optimized for a given operating system and CPU architecture. Here the main performance boost is prepared to reduce the JIT code that takes at startup time.

Crossgen related documents: https://github.com/dotnet/coreclr/blob/v2.1.3/Documentation/building/crossgen.md

Some pitfalls

I believe that every .NET Core programmers will encounter some of the following traps. I will try to explain these issues is how to generate.

Http Error 502.5 Process Failure

So far, the trap developers, the most frequently encountered or Azure Web Services are hosted in ASP.NET Core application in IIS. This problem usually occurs in the developer to upgrade a project, or when the application deployment target machine has not been updated. The real cause of the error is usually shared framework required version of the application can not be found, resulting in .NET Core application does not start properly. When dotnetUnable to start the application, IIS returns HTTP 502.5 error, but an internal error message is displayed.

"The specified framework was not found"

It was not possible to find any compatible framework version
The specified framework 'Microsoft.AspNetCore.App', version '2.1.3' was not found.
  - Check application dependencies and target a framework version installed at:
      /usr/local/share/dotnet/
  - Installing .NET Core prerequisites might help resolve this problem:
      http://go.microsoft.com/fwlink/?LinkID=798306&clcid=0x409
  - The .NET Core framework and SDK can be installed from:
      https://aka.ms/dotnet-download
  - The following versions are installed:
      2.1.1 at [/usr/local/share/dotnet/shared/Microsoft.AspNetCore.App]
      2.1.2 at [/usr/local/share/dotnet/shared/Microsoft.AspNetCore.App]

This error usually occurs after the HTTP 502.5 error, fault or Visual Studio Test Explorer.

As mentioned above, when the runtimeconfig.jsonfile specifies a name and version of the framework, but after retrieving properties and multi-level roll-forward strategy, the host still can not find a suitable framework version of the time, the above error occurs.

Upgrade Microsoft.AspNetCore.Appassembly Nuget package

Microsoft.AspNetCore.AppNuget bag assembly, does not provide sharing framework. It simply provides a C # / F # compiler to use some of the API as well as a small amount SDK. So you have to download and install the shared framework alone.

At the same time, due to the roll-forward strategy, you do not need an updated version of Nuget package to suit your program to run in the new version of the shared framework.

This may be a design error ASP.NET Core team, we can not be shared framework as a package Nuget appear in the project file. Packages sharing framework provided by the package is not in the usual sense. Unlike most programs in different packages, they are not self-sufficient. We hope that when the use of project <PackageReference>time, Nuget able to install all the necessary references, but frustrating is that the design of these special packages to deviate from our expectations model. Of course, now we've got various proposals to solve this problem. I hope it early date.

<PackageReference Include="Microsoft.AspNetCore.App" />

In ASP.NET Core 2.1's new project templates and documents, Microsoft showed off to developers, they only need to add the following line of code in the project file.

<PackageReference Include="Microsoft.AspNetCore.App" />

Other <PackageReference>reference code must be included Versionproperties. Only when the project file is <Project Sdk="Microsoft.NET.Sdk.Web">at the beginning, then the above phrase has nothing to do with the reference version of the package will work, and here only for Microsoft.AspNetCore.{App, All}the assembly package work. The Web SDK The other configuration items, for example: <TargetFramework>and <RuntimeIdentifier>to automatically select an appropriate version of the package.

If some of you to join cited in the package Versionproperties, and specify a version, or you do not use the Web SDK as the beginning of the project file, you can not use this feature. Here I find it difficult to recommend a good solution, because the best way to achieve this is based on your understanding of the level and type of project.

Posted trim (Publish Trimming)

When you use the dotnet publishcommand issued a framework for application-dependent, SDK will be used to restore the results of Nuget (restore result) to determine which assembly should appear in the published catalog. Some assembly is an assembly package by Nuget copies, and some will not, because they already appear in the shared frame.

It's easy to produce some error because ASP.NET Core as a shared framework and Nuget packages are available. Project Releases trim characteristics will try to check through a graphical mathematical transitive dependencies, and upgrades, and thus choosing the right package file.

Here we have a project reference to the following example:

<PackageReference Include="Microsoft.AspNetCore.App" Version="2.1.1" />
<PackageReference Include="Microsoft.AspNetCore.Mvc" Version="2.1.9" />

MVC is in fact Microsoft.AspNetCore.Appa part of, but when you call dotnet publishthe command to publish a project, you will find that your project selected after the upgrade Microsoft.AspNetCore.Mvc.dllpackage, this package than Microsoft.AspNetCore.Appis included in the 2.1.1 version is higher, so the final Microsoft.AspNetCore.Mvc.dllwill be copied to publish directory.

This is not ideal, because as your application size is growing, you never get ReadyToRunoptimized version Microsoft.AspNetCore.Mvc.dll.

PS: This question previously little noticed, but really common.

Confuse target framework nickname and sharing framework

If we simply think "netcoreapp2.0" == "Microsoft.NETCore.App, v2.0.0", you're wrong. Target framework nickname (Target Framework Moniker referred TFM) only by the project file <TargetFramework>specified node. "netcoreapp2.0" just wanted to human-friendly ways to show you which version of .NET Core.

TFM trap that its name is too short. It can not express the various shared framework, the former version of a particular patch of control, version roller, output type, and is an independent publishing or framework relies content publishing. The SDK will attempt to deduce the number of settings from TFM, but can not be inferred everything.

So, more accurately, "netcoreapp2.0" means "Microsoft.NETCore.App v2.0.0 or later."

Confuse project configuration

Finally, a trap and a related project configuration. Here there is a lot of terminology and configuration name, they are not always consistent. These terms are very confusing, so if you confuse these terms, it does not matter, it's not your fault.

Below, I list some common project settings and its practical implications.

<PropertyGroup>
  <TargetFramework>netcoreapp2.1</TargetFramework>
  <!--
    实际意义:
      * 从Nuget包解析编译引用时使用的API集合的版本
  -->

  <TargetFrameworks>netcoreapp2.1;net471</TargetFrameworks>
  <!--
    实际意义:
      * 使用两个不同的API集合版本进行编译。但这并不代表多层共享框架
  -->

  <MicrosoftNETPlatformLibrary>Microsoft.AspNetCore.App</MicrosoftNETPlatformLibrary>
  <!--
    实际意义:
      * 最顶层的共享框架名称
  -->

  <RuntimeFrameworkVersion>2.1.2</RuntimeFrameworkVersion>
  <!--
    实际意义:
      * 指定了Microsoft.AspNetCore.App程序包的版本,这个版本就是最小的共享框架版本
  -->

  <RuntimeIdentifier>win-x64</RuntimeIdentifier>
  <!--
    实际意义:
      * 操作系统种类 + CPU架构
  -->

  <RuntimeIdentifiers>win-x64;win-x86</RuntimeIdentifiers>
  <!--
    实际意义:
      * 运行此项目可能使用的操作系统种类和CPU架构列表,你必须要通过RuntimeIdentifier配置选择其中一个
  -->

</PropertyGroup>

<ItemGroup>

  <PackageReference Include="Microsoft.AspNetCore.App" Version="2.1.2" />
  <!--
    实际意义:
      * 使用Microsoft.AspNetCore.App作为共享框架
      * 最低版本2.1.2
  -->

  <PackageReference Include="Microsoft.AspNetCore.Mvc" Version="2.1.2" />
  <!--
    实际意义:
      * 引用Microsoft.AspNetCore.Mvc程序包
      * 实际版本2.1.2
  -->

  <FrameworkReference Include="Microsoft.AspNetCore.App" />
  <!--
    实际意义:
      * 使用Microsoft.AspNetCore.App作为共享框架.
  -->

</ItemGroup>

to sum up

Share .NET Core Framework as an optional feature, though flawed, but I think for most users, this is a reasonable default settings. I still think for .NET Core developers to understand the underlying principle is a good thing, I hope this is a good overview of the shared framework functions. I tried a number of related documents and guide the official website, so that you can find more information. If you have additional questions, please post a comment below.

Guess you like

Origin www.cnblogs.com/lwqlun/p/11802513.html
Recommended