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