Devuelva Thread.Abort () a .NET Core. Entrega de aplicaciones con su versión de CoreCLR y CoreFX

Al migrar de .NET Framework a .NET Core , pueden aparecer algunos momentos desagradables. Por ejemplo, si su aplicación usa dominios, tendrá que reescribir la lógica. Una situación similar con Thread.Abort () : a Microsoft no le gusta tanto esta práctica (y con razón) que primero declararon este método en desuso , y luego lo cortaron por completo del marco y ahora arrojan PlatformNotSupportedException traicioneramente.

Pero, ¿qué sucede si su aplicación usa Thread.Abort () y realmente desea traducirla a .NET Core sin reescribir nada? Bueno, sabemos muy bien que la plataforma incluso admite esta funcionalidad, así que puedo complacerte: hay una salida, solo necesitas ensamblar tu propia versión del CLR .

Descargo de responsabilidad: este es un artículo puramente práctico con un mínimo de teoría, diseñado solo para demostrar nuevas opciones de interacción entre el desarrollador y el entorno .NET. Nunca hagas esto en producción. Pero si realmente quieres ...



Esto fue posible gracias a dos cosas: el deseo de Microsoft de .NET Core multiplataforma y el trabajo realizado por los desarrolladores para transferir la fuente del marco al acceso abierto. Aprovechemos esto.

Mínimo teórico:

  • dotnet publishing nos permite publicar aplicaciones independientes : el marco se entregará con él y no se buscará en algún lugar del GAC
  • La versión de CoreCLR en la que se ejecutará la aplicación, bajo ciertas condiciones, se puede configurar usando runtimeconfig.json
  • Podemos construir nuestro propio CoreFX : github.com/dotnet/corefx
  • Podemos construir nuestro propio CoreCLR : github.com/dotnet/coreclr

Personaliza CoreFX


Antes de pasar a nuestro objetivo principal, devolver Thread.Abort ( ), cambiemos algo fundamental en CoreFX para que se caliente y pruebe la funcionalidad de todas las herramientas. Por ejemplo, siguiendo los pasos de mi artículo anterior sobre dinámica , prohibimos por completo su uso en la aplicación. Por qué Porque podemos

Prerrequisitos


En primer lugar, instalaremos todo lo necesario para el ensamblaje:

  • CMake
  • Vista previa de Visual Studio 2019
  • Último SDK de .NET Core (vista previa de .NET Core 3.0)

Visual Studio 2019 - Cargas de trabajo


Desarrollo de escritorio .NET

  • Todos los componentes requeridos
  • .NET Framework 4.7.2 Herramientas de desarrollo

Desarrollo de escritorio con C ++

  • Todos los componentes requeridos
  • Conjunto de herramientas VC ++ 2019 v142 (x86, x64)
  • Windows 8.1 SDK y UCRT SDK
  • Conjunto de herramientas VC ++ 2017 v141 (x86, x64)

Desarrollo multiplataforma de .NET Core

  • Todos los componentes requeridos

Visual Studio 2019: componentes individuales


  • Compiladores de C # y Visual Basic Roslyn
  • Herramientas de análisis estático
  • Paquete de orientación de biblioteca portátil .NET
  • Windows 10 SDK o Windows 8.1 SDK
  • Características principales de Visual Studio C ++
  • Conjunto de herramientas VC ++ 2019 v142 (x86, x64)
  • Conjunto de herramientas VC ++ 2017 v141 (x86, x64)
  • Msbuild
  • .NET Framework 4.7.2 Paquete de orientación
  • Windows Universal CRT SDK

Clon corefx :

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

Ahora deshabilitar dinámico . Abriremos para esto (en adelante indicaré las rutas relativas a la raíz del repositorio)

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

Y al final de la función CallSite <T> .Create, inserte el código simple:

 throw new PlatformNotSupportedException("No way"); 

Regresamos a corefx y ejecutamos build.cmd . Una vez completado el ensamblaje, cree un nuevo proyecto .NET Core en Visual Studio con los siguientes contenidos:

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

Compilamos nuestro proyecto. Ahora ve a

 corefx\artifacts\packages\Debug\NonShipping 

y encontramos un paquete que se parece a esto: Microsoft.Private.CoreFx.NETCoreApp. 5.0.0-dev.19465.1 .nupkg . Abrimos .csproj de nuestro proyecto e insertamos allí las siguientes líneas:

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

La versión debe ser la misma que en el nombre del paquete ensamblado. En mi caso, 5.0.0-dev.19465.1 .



Vaya a la configuración de nuget para nuestro proyecto y agregue dos nuevas rutas allí:

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

Y desmarca todos los demás.



Ve a la carpeta del proyecto y ejecuta

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

Hecho Solo queda correr:



Funciona! Las bibliotecas no se toman del GAC , la dinámica no funciona.

Haga que CoreCLR sea grandioso nuevamente


Ahora pasemos a la segunda parte, devolviendo Thread.Abort () . Aquí nos espera una sorpresa desagradable: la implementación de subprocesos reside en CoreCLR , que no forma parte de CoreFX y está preinstalado en la máquina por separado. Primero, cree un proyecto de demostración:

 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 coreclr . Encuentra el archivo

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

Y reemplace Abort () con

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

Ahora necesitamos devolver los atributos y la implementación de c ++ . Lo recogí en partes de varios repositorios abiertos de .NET Framework y, por conveniencia, diseñé todos los cambios en forma de solicitud de extracción .

Nota: al construir, hubo problemas con los recursos en los atributos "nuevos", que yo
"Fijo" con enchufes. Tenga esto en cuenta si desea utilizar este código en cualquier lugar que no sea la experimentación en el hogar.

Después de integrar estos cambios en el código, ejecute build.cmd desde coreclr . El ensamblaje en las etapas posteriores puede comenzar a rociar con errores, pero no da miedo, lo principal para nosotros es que CoreCLR puede ensamblar. Mentirá en:

 coreclr\bin\Product\Windows_NT.x64.Debug 

Manera fácil


Llevamos a cabo

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

Los archivos de Windows_NT.x64.Debug se colocan en la carpeta con la aplicación publicada.

Camino duro


Una vez que las bibliotecas estén ensambladas, vaya a

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

y clonar la carpeta 3.0.0. Lo llamaremos, por ejemplo, 5.0.1. Copiamos todo lo que se encuentra en Windows_NT.x64.Debug , excepto las carpetas. Ahora nuestra versión de CoreCLR estará disponible a través de runtimeconfig.

Poniendo nuestro proyecto juntos. Añadir a .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> <PackageConflictPreferredPackages> Microsoft.Private.CoreFx.NETCoreApp ;. tiempo de ejecución de $ (RuntimeIdentifiers) .Microsoft.Private.CoreFx.NETCoreApp; $ (PackageConflictPreferredPackages) </ PackageConflictPreferredPackages> <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 las manipulaciones con nuget de la parte anterior del artículo. Publicar

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

En runtimeconfig.json, ingrese la siguiente configuración:

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

Resultado


Lanzamiento



La magia sucedió. Ahora en nuestras aplicaciones .NET Core Thread.Abort () se está ejecutando nuevamente. Pero, por supuesto, solo en Windows .

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


All Articles