Retorne Thread.Abort () para o .NET Core. Entrega de aplicativos com sua versão do CoreCLR e CoreFX

Ao migrar do .NET Framework para o .NET Core , alguns momentos desagradáveis ​​podem surgir. Por exemplo, se seu aplicativo usar domínios, você precisará reescrever a lógica. Uma situação semelhante ao Thread.Abort () : A Microsoft não gosta tanto dessa prática (e com razão) que primeiro declarou esse método como obsoleto e depois o cortou completamente da estrutura e agora está lançando traiçoeiramente uma PlatformNotSupportedException .

Mas e se o seu aplicativo usar Thread.Abort () e você realmente quiser convertê- lo para o .NET Core sem reescrever nada? Bem, sabemos muito bem que a plataforma suporta até essa funcionalidade, para que eu possa agradá-lo: existe uma saída, você só precisa montar sua própria versão do CLR .

Isenção de responsabilidade: este é um artigo puramente prático, com um mínimo de teoria, projetado apenas para demonstrar novas opções de interação entre o desenvolvedor e o ambiente .NET. Nunca faça isso na produção. Mas se você realmente quer ...



Isso foi possível graças a duas coisas: o desejo da Microsoft de usar o .NET Core entre plataformas e o trabalho realizado pelos desenvolvedores para transferir o código-fonte da estrutura para abrir o acesso. Vamos aproveitar isso.

Mínimo teórico:

  • A publicação dotnet nos permite publicar aplicativos independentes : a estrutura será entregue com ele e não será pesquisada em algum lugar no GAC
  • A versão do CoreCLR na qual o aplicativo será executado, sob certas condições, pode ser configurada usando runtimeconfig.json
  • Podemos criar nosso próprio CoreFX : github.com/dotnet/corefx
  • Podemos criar nosso próprio CoreCLR : github.com/dotnet/coreclr

Personalizar CoreFX


Antes de prosseguir para o nosso objetivo principal - retornar o Thread.Abort ( ) - vamos mudar algo fundamental no CoreFX para aquecer e testar a funcionalidade de todas as ferramentas. Por exemplo, nos passos do meu artigo anterior sobre dinâmico , proibimos completamente seu uso no aplicativo. Porque Porque nós podemos.

Pré-requisitos


Antes de tudo, instalaremos tudo o necessário para a montagem:

  • CMake
  • Visualização do Visual Studio 2019
  • SDK do .NET Core mais recente (visualização do .NET Core 3.0)

Visual Studio 2019 - Cargas de trabalho


Desenvolvimento de desktop .NET

  • Todos os componentes necessários
  • Ferramentas de desenvolvimento do .NET Framework 4.7.2

Desenvolvimento de desktop com C ++

  • Todos os componentes necessários
  • Conjunto de ferramentas VC ++ 2019 v142 (x86, x64)
  • Windows 8.1 SDK e UCRT SDK
  • Conjunto de ferramentas VC ++ 2017 v141 (x86, x64)

Desenvolvimento entre plataformas do .NET Core

  • Todos os componentes necessários

Visual Studio 2019 - Componentes individuais


  • Compiladores C # e Visual Basic Roslyn
  • Ferramentas de análise estática
  • Pacote de segmentação de biblioteca portátil do .NET
  • Windows 10 SDK ou Windows 8.1 SDK
  • Recursos principais do Visual Studio C ++
  • Conjunto de ferramentas VC ++ 2019 v142 (x86, x64)
  • Conjunto de ferramentas VC ++ 2017 v141 (x86, x64)
  • Msbuild
  • Pacote de direcionamento do .NET Framework 4.7.2
  • Windows Universal CRT SDK

Clone corefx :

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

Agora desative o dinâmico . Abriremos para isso (a seguir, indicarei os caminhos relativos à raiz do repositório)

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

E no final da função CallSite <T> .Create , insira o código simples:

 throw new PlatformNotSupportedException("No way"); 

Retornamos ao corefx e executamos o build.cmd . Após a conclusão da montagem, crie um novo projeto do .NET Core no Visual Studio com o seguinte conteúdo:

 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); } } 

Nós compilamos nosso projeto. Agora vá para

 corefx\artifacts\packages\Debug\NonShipping 

e encontramos um pacote que se parece com isso: Microsoft.Private.CoreFx.NETCoreApp. 5.0.0-dev.19465.1 .nupkg . Abrimos .csproj do nosso projeto e inserimos as seguintes linhas:

 <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> 

A versão deve ser a mesma do nome do pacote montado. No meu caso, 5.0.0-dev.19465.1 .



Vá para as configurações de nuget do nosso projeto e adicione dois novos caminhos:

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

E desmarque todos os outros.



Vá para a pasta do projeto e execute

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

Feito! Resta apenas executar:



Isso funciona! As bibliotecas não são retiradas do GAC , a dinâmica não funciona.

Torne o CoreCLR ótimo novamente


Agora vamos para a segunda parte, retornando Thread.Abort () . Uma surpresa desagradável nos espera aqui: a implementação do encadeamento está no CoreCLR , que não faz parte do CoreFX e é pré-instalado na máquina separadamente. Primeiro, crie um projeto de demonstração:

 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(); 

Desinflar o coreclr . Encontre o arquivo

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

E substitua Abort () por

 [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(); 

Agora precisamos retornar os atributos e a implementação do c ++ . Eu o colecionei em pedaços de vários repositórios abertos do .NET Framework e, por conveniência, projetei todas as alterações na forma de uma solicitação pull .

Nota: ao construir, houve problemas com recursos nos atributos "novos", que eu
"Fixo" com plugues. Lembre-se disso se desejar usar esse código em outro lugar que não seja a experimentação em casa.

Após integrar essas alterações no código, execute build.cmd a partir do coreclr . A montagem nos estágios posteriores pode começar a polvilhar com erros, mas não é assustador, a principal coisa para nós é que o CoreCLR pode montar. Ele estará em:

 coreclr\bin\Product\Windows_NT.x64.Debug 

Maneira fácil


Realizamos

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

Os arquivos do Windows_NT.x64.Debug são descartados na pasta com o aplicativo publicado.

Maneira difícil


Depois que as bibliotecas estiverem montadas, vá para

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

e clone a pasta 3.0.0. Vamos chamá-lo, por exemplo, 5.0.1. Copiamos tudo o que está no Windows_NT.x64.Debug , exceto as pastas. Agora nossa versão do CoreCLR estará disponível no runtimeconfig.

Montando nosso projeto. Adicione ao .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> 

Repetimos as manipulações com pepitas da parte anterior do artigo. Publicar

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

Em runtimeconfig.json, insira a seguinte configuração:

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

Resultado


Lançamento!



A mágica aconteceu. Agora, em nossos aplicativos .NET Core , o Thread.Abort () está sendo executado novamente. Mas, é claro, apenas no Windows .

Source: https://habr.com/ru/post/pt467475/


All Articles