Lors de la migration du
.NET Framework vers le
.NET Core , certains moments désagréables peuvent survenir. Par exemple, si votre application utilise des domaines, vous devrez réécrire la logique. Une situation similaire avec
Thread.Abort () :
Microsoft est tellement
détesté par cette pratique (et à juste titre) qu'ils ont d'abord déclaré cette méthode
obsolète , puis l'ont complètement supprimée du cadre et maintenant, elle lance de manière perfide une
exception PlatformNotSupportedException .
Mais que se passe-t-il si votre application utilise
Thread.Abort () et que vous souhaitez
vraiment la traduire en
.NET Core sans réécrire quoi que ce soit? Eh bien, nous savons très bien que la plate-forme prend même en charge cette fonctionnalité, je peux donc vous plaire: il existe un moyen de sortir, il vous suffit d'assembler votre propre version du
CLR .
Avertissement: Il s'agit d'un article purement pratique avec un minimum de théorie, conçu uniquement pour démontrer de nouvelles options d'interaction entre le développeur et l'environnement .NET. Ne faites jamais cela en production. Mais si vous voulez vraiment ...
Cela a été rendu possible grâce à deux choses:
la volonté
de Microsoft de multiplier les plates-formes
.NET Core et le travail effectué par les développeurs pour transférer le code source du framework en accès ouvert. Profitons de cela.
Minimum théorique:
- dotnet publish nous permet de publier une application autonome : le framework sera livré avec, et non recherché quelque part dans le GAC
- La version de CoreCLR sur laquelle l'application s'exécutera, sous certaines conditions, peut être définie à l'aide de runtimeconfig.json
- Nous pouvons créer notre propre CoreFX : github.com/dotnet/corefx
- Nous pouvons construire notre propre CoreCLR : github.com/dotnet/coreclr
Personnalisez CoreFX
Avant de passer Ă notre objectif principal - retourner
Thread.Abort ( ) - changeons quelque chose de fondamental dans
CoreFX pour nous
réchauffer et tester la fonctionnalité de tous les outils. Par exemple, sur les traces de mon
précédent article sur la
dynamique , nous interdisons complètement son utilisation dans l'application. Pourquoi? Parce que nous le pouvons.
Prérequis
Tout d'abord, nous installerons
tout le nécessaire pour le montage:
- CMake
- Aperçu de Visual Studio 2019
- Dernier SDK .NET Core (.NET Core 3.0 Preview)
Visual Studio 2019 - Charges de travail
Développement de bureau .NET- Tous les composants requis
- .NET Framework 4.7.2 Outils de développement
Développement de bureau avec C ++- Tous les composants requis
- VC ++ 2019 v142 Toolset (x86, x64)
- SDK Windows 8.1 et SDK UCRT
- VC ++ 2017 v141 Toolset (x86, x64)
Développement multiplateforme .NET Core- Tous les composants requis
Visual Studio 2019 - Composants individuels
- Compilateurs Roslyn C # et Visual Basic
- Outils d'analyse statique
- Pack de ciblage de bibliothèque portable .NET
- SDK Windows 10 ou SDK Windows 8.1
- Fonctionnalités principales de Visual Studio C ++
- VC ++ 2019 v142 Toolset (x86, x64)
- VC ++ 2017 v141 Toolset (x86, x64)
- Msbuild
- Pack de ciblage .NET Framework 4.7.2
- SDK CRT universel Windows
Clone corefx :
git clone https://github.com/dotnet/corefx.git
Désactivez maintenant la
dynamique . Nous allons ouvrir pour cela (ci-après je vais indiquer les chemins par rapport à la racine du référentiel)
corefx\src\System.Linq.Expressions\src\System\Runtime\CompilerServices\CallSite.cs
Et Ă la fin de la fonction
CallSite <T>
.Create, insérez le code brut:
throw new PlatformNotSupportedException("No way");
Nous revenons Ă
corefx et
exécutons build.cmd . Une fois l'assemblage terminé, créez un nouveau projet
.NET Core dans
Visual Studio avec le contenu suivant:
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); }
Nous compilons notre projet. Maintenant, allez Ă
corefx\artifacts\packages\Debug\NonShipping
et nous y trouvons un package qui ressemble Ă ceci:
Microsoft.Private.CoreFx.NETCoreApp. 5.0.0-dev.19465.1 .nupkg . Nous ouvrons
.csproj de notre projet et y insérons les lignes suivantes:
<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 version doit être la même que dans le nom du package assemblé. Dans mon cas,
5.0.0-dev.19465.1 .

Accédez aux paramètres de
nuget pour notre projet et ajoutez-y deux nouveaux chemins:
corefx\artifacts\packages\Debug\NonShipping corefx\artifacts\packages\Debug\Shipping
Et décochez toutes les autres.

Accédez au dossier du projet et exécutez
dotnet publish --runtime win-x64 --self-contained
C'est fait! Il ne reste plus qu'à exécuter:

Ça marche! Les bibliothèques ne sont pas extraites du
GAC , la
dynamique ne fonctionne pas.
Rendre CoreCLR grand Ă nouveau
Passons maintenant à la deuxième partie, en retournant
Thread.Abort () . Une désagréable surprise nous attend ici: l'implémentation des
threads réside dans
CoreCLR , qui ne fait pas partie de
CoreFX et est préinstallé sur la machine séparément. Créez d'abord un projet de démonstration:
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();
Dégonfler le coreclr . Trouvez le fichier
coreclr\src\System.Private.CoreLib\shared\System\Threading\Thread.cs
Et remplacez
Abort () par
[SecuritySafeCritical] [SecurityPermissionAttribute(SecurityAction.Demand, ControlThread = true)] public void Abort() { AbortInternal(); } [System.Security.SecurityCritical]
Nous devons maintenant renvoyer les attributs et l'implémentation
c ++ . Je l'ai collecté en morceaux à partir de divers référentiels ouverts du
.NET Framework et pour plus de commodité, j'ai conçu toutes les modifications sous la forme d'une
demande d'extraction .
Remarque: lors de la construction, il y avait des problèmes de ressources dans les «nouveaux» attributs,
"Fixe" avec des bouchons. Gardez cela à l'esprit si vous souhaitez utiliser ce code ailleurs que dans l'expérimentation à domicile.Après avoir intégré ces modifications dans le code, exécutez
build.cmd Ă partir de
coreclr . L'assemblage dans les étapes ultérieures peut commencer à parsemer d'erreurs, mais ce n'est pas effrayant, l'essentiel pour nous est que
CoreCLR puisse s'assembler. Il se situera dans:
coreclr\bin\Product\Windows_NT.x64.Debug
Moyen facile
Nous réalisons
dotnet publish --runtime win-x64 --self-contained
Les fichiers de
Windows_NT.x64.Debug sont déposés dans le dossier avec l'application publiée.
Chemin difficile
Une fois les bibliothèques assemblĂ©es, accĂ©dez Ă
C:\Program Files\dotnet\shared\Microsoft.NETCore.App
et clonez le dossier 3.0.0. Nous l'appellerons, par exemple, 5.0.1. Nous copions tout ce qui se trouve dans
Windows_NT.x64.Debug , Ă l'exception des dossiers. Maintenant, notre version de
CoreCLR sera disponible via runtimeconfig.
Monter notre projet. Ajoutez Ă
.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>
Nous répétons les manipulations avec
nuget de la partie précédente de l'article. Publier
dotnet publish --runtime win-x64 --self-contained
Dans
runtimeconfig.json, entrez la configuration suivante:
{ "runtimeOptions": { "tfm": "netcoreapp3.0", "framework": { "name": "Microsoft.NETCore.App", "version": "5.0.1" } } }
Résultat
Lancez!

La magie s'est produite. Maintenant, dans nos applications
.NET Core ,
Thread.Abort () est à nouveau en cours d'exécution. Mais, bien sûr, uniquement sur
Windows .