将Thread.Abort()返回.NET Core。 带有其版本的CoreCLR和CoreFX的应用程序交付

.NET Framework迁移到.NET Core时 ,可能会出现一些不愉快的情况。 例如,如果您的应用程序使用域,则必须重写逻辑。 Thread.Abort()的情况与此类似: 微软对此实践非常不满意 (正确的做法是),他们首先声明不赞成使用此方法,然后将其完全从框架中删除,而现在却在诡异地抛出PlatformNotSupportedException

但是,如果您的应用程序使用Thread.Abort() ,并且您真的想将其转换为.NET Core而不重写任何内容,该怎么办? 好吧,我们非常清楚该平台甚至支持此功能,所以我可以请您:有一种出路,您只需要组装自己的CLR版本即可。

免责声明:这是一篇纯实践性的文章,几乎没有理论知识,仅用于演示开发人员与.NET环境之间交互的新选项。 绝对不要在生产中这样做。 但是,如果您真的想...



之所以能够做到这一点,要归功于两件事: 微软对跨平台.NET Core 渴望以及开发人员为将框架的源代码转移到开放访问而进行的工作。 让我们利用这一点。

理论最小值:

  • dotnet publish允许我们发布独立的应用程序:框架将随框架一起提供,而不是在GAC中的任何位置进行搜索
  • 可以使用runtimeconfig.json设置在某些条件下运行应用程序的CoreCLR版本。
  • 我们可以构建自己的CoreFXgithub.com/dotnet/corefx
  • 我们可以构建自己的CoreCLRgithub.com/dotnet/coreclr

自定义CoreFX


在继续我们的主要目标(返回Thread.Abort( ))之前,让我们更改CoreFX中的一些基本功能以进行热身以测试所有工具的功能。 例如,在上一篇有关dynamic的 文章中 ,我们完全禁止在应用程序中使用它。 怎么了 因为我们可以。

先决条件


首先,我们将安装组装所需一切

  • CMake的
  • Visual Studio 2019预览版
  • 最新的.NET Core SDK(.NET Core 3.0预览版)

Visual Studio 2019-工作负载


.NET桌面开发

  • 所有必需的组件
  • .NET Framework 4.7.2开发工具

使用C ++进行桌面开发

  • 所有必需的组件
  • VC ++ 2019 v142工具集(x86,x64)
  • Windows 8.1 SDK和UCRT SDK
  • VC ++ 2017 v141工具集(x86,x64)

.NET Core跨平台开发

  • 所有必需的组件

Visual Studio 2019-各个组件


  • C#和Visual Basic Roslyn编译器
  • 静态分析工具
  • .NET便携式库目标包
  • Windows 10 SDK或Windows 8.1 SDK
  • Visual Studio C ++核心功能
  • VC ++ 2019 v142工具集(x86,x64)
  • VC ++ 2017 v141工具集(x86,x64)
  • 编译器
  • .NET Framework 4.7.2目标包
  • Windows通用CRT SDK

克隆corefx

git clone https://github.com/dotnet/corefx.git 

现在禁用动态功能 。 我们将为此打开(此后,我将指示相对于存储库根的路径)

 corefx\src\System.Linq.Expressions\src\System\Runtime\CompilerServices\CallSite.cs 

CallSite <T> .Create函数的末尾,插入普通代码:

 throw new PlatformNotSupportedException("No way"); 

我们返回corefx并执行build.cmd 。 组装完成后,在Visual Studio中使用以下内容创建一个新的.NET Core项目:

 public int Test { get; set; } public static void Main(string[] args) { try { dynamic a = new Program(); a.Test = 120; } catch (Exception e) { Console.WriteLine(e); } //,    foreach (var asm in AppDomain.CurrentDomain.GetAssemblies()) { Console.WriteLine(asm.Location); } } 

我们编译我们的项目。 现在去

 corefx\artifacts\packages\Debug\NonShipping 

我们找到一个看起来像这样的包: Microsoft.Private.CoreFx.NETCoreApp。 5.0.0-dev.19465.1 .nu​​pkg 。 我们打开项目的.csproj并在其中插入以下行:

 <PropertyGroup> <PackageConflictPreferredPackages>Microsoft.Private.CoreFx.NETCoreApp;runtime.$(RuntimeIdentifiers).Microsoft.Private.CoreFx.NETCoreApp;$(PackageConflictPreferredPackages)</PackageConflictPreferredPackages> </PropertyGroup> <ItemGroup> <PackageReference Include="Microsoft.Private.CoreFx.NETCoreApp" Version="5.0.0-dev.19465.1" /> </ItemGroup> 

版本应与组装好的包装名称相同。 就我而言,是5.0.0-dev.19465.1



转到我们项目的nuget设置,并在其中添加两个新路径:

 corefx\artifacts\packages\Debug\NonShipping corefx\artifacts\packages\Debug\Shipping 

并取消选中所有其他。



转到项目文件夹并执行

 dotnet publish --runtime win-x64 --self-contained 

做完了! 它仍然只能运行:



有效! 库不是从GAC提取的, 动态的是行不通的。

使CoreCLR再次出色


现在让我们继续第二部分,返回Thread.Abort() 。 一个令人不愉快的惊喜在这里等待着我们: 线程实现位于CoreCLR中 ,它不是CoreFX的一部分, 而是预先安装在机器上。 首先,创建一个演示项目:

 var runtimeInformation = RuntimeInformation.FrameworkDescription; Console.WriteLine(runtimeInformation); var thr = new Thread(() => { try { while (true) { Console.WriteLine("."); Thread.Sleep(500); } } catch (ThreadAbortException) { Console.WriteLine("Thread aborted!"); } }); foreach (var asm in AppDomain.CurrentDomain.GetAssemblies()) { Console.WriteLine(asm.Location); } thr.Start(); Thread.Sleep(2000); thr.Abort(); 

压缩coreclr 。 查找文件

 coreclr\src\System.Private.CoreLib\shared\System\Threading\Thread.cs 

并将Abort()替换为

 [SecuritySafeCritical] [SecurityPermissionAttribute(SecurityAction.Demand, ControlThread = true)] public void Abort() { AbortInternal(); } [System.Security.SecurityCritical] // auto-generated [ResourceExposure(ResourceScope.None)] [MethodImplAttribute(MethodImplOptions.InternalCall)] private extern void AbortInternal(); 

现在我们需要返回属性和c ++实现。 我从.NET Framework的各种开放存储库中分批收集了这些信息,为方便起见,我以拉取请求的形式设计了所有更改。

注意:构建时,“新”属性中的资源存在问题,我
带插头“固定”。 如果您想在家庭实验以外的任何地方使用此代码,请记住这一点。

将这些更改集成到代码中后,运行coreclr的 build.cmd 。 后期的组装可能会开始出现错误,但这并不可怕,对我们而言,主要是CoreCLR可以组装。 它将位于:

 coreclr\bin\Product\Windows_NT.x64.Debug 

简单的方法


我们执行

 dotnet publish --runtime win-x64 --self-contained 

Windows_NT.x64.Debug中的文件将与发布的应用程序一起放入文件夹。

艰难的道路


库组装完成后,转到

 C:\Program Files\dotnet\shared\Microsoft.NETCore.App 

并克隆文件夹3.0.0。 我们将其命名为例如5.0.1。 我们复制Windows_NT.x64.Debug中所有内容(文件夹除外)。 现在,我们的CoreCLR版本将通过runtimeconfig可用。

将我们的项目放在一起。 添加到.csproj

 <PropertyGroup> <DisableImplicitFrameworkReferences>true</DisableImplicitFrameworkReferences> <PackageConflictPreferredPackages>Microsoft.Private.CoreFx.NETCoreApp;runtime.$(RuntimeIdentifiers).Microsoft.Private.CoreFx.NETCoreApp;$(PackageConflictPreferredPackages)</PackageConflictPreferredPackages> </PropertyGroup> <ItemGroup> <PackageReference Include="Microsoft.Private.CoreFx.NETCoreApp" Version="5.0.0-dev.19465.1" /> </ItemGroup> 

我们使用本文前面部分中的nuget重复操作。 发布

 dotnet publish --runtime win-x64 --self-contained 

runtimeconfig.json中,输入以下配置:

 { "runtimeOptions": { "tfm": "netcoreapp3.0", "framework": { "name": "Microsoft.NETCore.App", "version": "5.0.1" } } } 

结果


发射!



魔术发生了。 现在,在我们的.NET Core应用程序中, Thread.Abort()再次运行。 但是,当然,仅在Windows上

Source: https://habr.com/ru/post/zh-CN467475/


All Articles