Geben Sie Thread.Abort () an .NET Core zurück. Anwendungsbereitstellung mit der Version von CoreCLR und CoreFX

Bei der Migration von .NET Framework auf .NET Core können einige unangenehme Momente auftreten. Wenn Ihre Anwendung beispielsweise Domänen verwendet, müssen Sie die Logik neu schreiben. Eine ähnliche Situation mit Thread.Abort () : Microsoft ist von dieser Vorgehensweise (und das zu Recht) so unzufrieden, dass sie diese Methode zuerst für veraltet erklärt und dann vollständig aus dem Framework herausgeschnitten haben. Jetzt wird auf verräterische Weise eine PlatformNotSupportedException ausgelöst .

Aber was ist, wenn Ihre Anwendung Thread.Abort () verwendet und Sie sie wirklich in .NET Core übersetzen möchten, ohne etwas neu zu schreiben? Wir wissen sehr gut, dass die Plattform diese Funktionalität sogar unterstützt, daher kann ich Ihnen gefallen: Es gibt einen Ausweg, Sie müssen nur Ihre eigene Version der CLR zusammenstellen .

Haftungsausschluss: Dies ist ein rein praktischer Artikel mit einem Minimum an Theorie, der nur neue Optionen für die Interaktion zwischen dem Entwickler und der .NET-Umgebung demonstrieren soll. Mach das niemals in der Produktion. Aber wenn du wirklich willst ...



Möglich wurde dies durch zwei Dinge: Microsofts Wunsch nach plattformübergreifendem .NET Core und die Arbeit der Entwickler, den Quellcode des Frameworks auf Open Access zu übertragen. Lassen Sie uns dies ausnutzen.

Theoretisches Minimum:

  • Mit dotnet Publish können wir eigenständige Anwendungen veröffentlichen: Das Framework wird mitgeliefert und nicht irgendwo im GAC durchsucht
  • Die Version von CoreCLR, auf der die Anwendung unter bestimmten Bedingungen ausgeführt wird, kann mit runtimeconfig.json festgelegt werden
  • Wir können unser eigenes CoreFX erstellen : github.com/dotnet/corefx
  • Wir können unsere eigene CoreCLR erstellen: github.com/dotnet/coreclr

Passen Sie CoreFX an


Bevor wir zu unserem Hauptziel übergehen - Thread.Abort ( ) zurückzugeben - ändern wir etwas Grundlegendes in CoreFX , um die Funktionalität aller Tools zu testen. In den Fußstapfen meines vorherigen Artikels über Dynamik verbieten wir beispielsweise die Verwendung in der Anwendung vollständig. Warum? Weil wir können.

Voraussetzungen


Zunächst installieren wir alles, was für die Montage erforderlich ist :

  • CMake
  • Visual Studio 2019 Vorschau
  • Neuestes .NET Core SDK (Vorschau auf .NET Core 3.0)

Visual Studio 2019 - Workloads


.NET Desktop-Entwicklung

  • Alle erforderlichen Komponenten
  • .NET Framework 4.7.2 Entwicklungstools

Desktop-Entwicklung mit C ++

  • Alle erforderlichen Komponenten
  • VC ++ 2019 v142 Toolset (x86, x64)
  • Windows 8.1 SDK und UCRT SDK
  • VC ++ 2017 v141 Toolset (x86, x64)

Plattformübergreifende .NET Core-Entwicklung

  • Alle erforderlichen Komponenten

Visual Studio 2019 - Einzelne Komponenten


  • C # und Visual Basic Roslyn Compiler
  • Statische Analysewerkzeuge
  • Targeting Pack für tragbare .NET-Bibliotheken
  • Windows 10 SDK oder Windows 8.1 SDK
  • Visual Studio C ++ - Kernfunktionen
  • VC ++ 2019 v142 Toolset (x86, x64)
  • VC ++ 2017 v141 Toolset (x86, x64)
  • Msbuild
  • .NET Framework 4.7.2 Targeting Pack
  • Windows Universal CRT SDK

Klone corefx :

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

Deaktivieren Sie jetzt die Dynamik . Wir werden uns dafür öffnen (im Folgenden werde ich die Pfade relativ zum Stammverzeichnis des Repositorys angeben.)

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

Fügen Sie am Ende der CallSite <T> .Create-Funktion den einfachen Code ein:

 throw new PlatformNotSupportedException("No way"); 

Wir kehren zu corefx zurück und führen build.cmd aus . Erstellen Sie nach Abschluss der Assembly ein neues .NET Core- Projekt in Visual Studio mit den folgenden Inhalten:

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

Wir stellen unser Projekt zusammen. Jetzt geh zu

 corefx\artifacts\packages\Debug\NonShipping 

und wir finden dort ein Paket, das ungefähr so ​​aussieht: Microsoft.Private.CoreFx.NETCoreApp. 5.0.0-dev.19465.1 .nupkg . Wir öffnen .csproj unseres Projekts und fügen dort die folgenden Zeilen ein:

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

Die Version sollte mit der im Namen des zusammengestellten Pakets übereinstimmen. In meinem Fall 5.0.0-dev.19465.1 .



Gehen Sie zu den Nuget- Einstellungen für unser Projekt und fügen Sie dort zwei neue Pfade hinzu:

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

Und deaktivieren Sie alle anderen.



Gehen Sie zum Projektordner und führen Sie ihn aus

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

Fertig! Es bleibt nur zu laufen:



Es funktioniert! Bibliotheken werden nicht aus dem GAC entnommen, Dynamik funktioniert nicht.

Machen Sie CoreCLR wieder großartig


Fahren wir nun mit dem zweiten Teil fort und geben Thread.Abort () zurück . Hier erwartet uns eine unangenehme Überraschung: Die Thread- Implementierung liegt in CoreCLR , das nicht Teil von CoreFX ist und separat auf dem Computer vorinstalliert ist. Erstellen Sie zunächst ein Demo-Projekt:

 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 entleeren . Suchen Sie die Datei

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

Und ersetzen Sie Abort () durch

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

Jetzt müssen wir die Attribute und die C ++ - Implementierung zurückgeben. Ich habe es in Teilen aus verschiedenen offenen Repositorys von .NET Framework gesammelt und der Einfachheit halber alle Änderungen in Form einer Pull-Anfrage entworfen .

Hinweis: Beim Erstellen gab es Probleme mit Ressourcen in den "neuen" Attributen, die ich
"Fest" mit Steckern. Denken Sie daran, wenn Sie diesen Code an einem anderen Ort als zu Hause verwenden möchten.

Führen Sie nach der Integration dieser Änderungen in den Code build.cmd von coreclr aus . Die Montage in den späteren Phasen kann mit Fehlern übersät sein, aber es ist nicht beängstigend. Die Hauptsache für uns ist, dass CoreCLR zusammengebaut werden kann. Es wird liegen in:

 coreclr\bin\Product\Windows_NT.x64.Debug 

Einfacher Weg


Wir führen aus

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

Dateien von Windows_NT.x64.Debug werden mit der veröffentlichten Anwendung in den Ordner verschoben .

Harter Weg


Sobald die Bibliotheken zusammengestellt sind, gehen Sie zu

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

und klonen Sie den Ordner 3.0.0. Wir werden es zum Beispiel 5.0.1 nennen. Wir kopieren dort alles, was in Windows_NT.x64.Debug liegt, mit Ausnahme der Ordner. Jetzt wird unsere Version von CoreCLR über runtimeconfig verfügbar sein.

Unser Projekt zusammenstellen. Zu .csproj hinzufügen :

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

Wir wiederholen die Manipulationen mit Nuget aus dem vorherigen Teil des Artikels. Veröffentlichen

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

Geben Sie in runtimeconfig.json die folgende Konfiguration ein:

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

Ergebnis


Starten Sie!



Die Magie ist passiert. In unseren .NET Core- Anwendungen wird Thread.Abort () jetzt wieder ausgeführt. Aber natürlich nur unter Windows .

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


All Articles