Portieren von WPF-Anwendungen auf Netcore 3.0

Mit der kommenden Version von Netcore 3.0 können Sie wpf auf Netcore ausführen. Der Übersetzungsvorgang für ein einfaches Projekt dauert ein bis zwei Tage. Jeder nachfolgende ist viel schneller.







Vorbereitung und Umsetzung von Projekten



Der erste Schritt bei der Vorbereitung ist die Installation und Ausführung von Portability Analyzer. Bei der Ausgabe erhalten wir eine Excel-Platte, in der wir sehen, wie sehr unser Code die neuen Anforderungen erfüllt.





Das Verfahren zum Konvertieren alter Projekte wurde in mehreren Schritten durchgeführt.


  1. Microsoft empfiehlt, die Framework-Version für ältere Projekte auf .NET Framework 4.7.3 zu aktualisieren.
  2. Konvertieren Sie die Struktur alter Projekte in ein neues Format. Ersetzen Sie packages.config durch PackageReference.
  3. Drittens passen Sie die Struktur der csproj-Datei an das Netcore-Format an.


Ich möchte Emil Yangirov mit seinem Bericht über die Migration zu Netcore danken, der sehr nützlich war. Link zu seinem Bericht.



Es stellte sich heraus, dass wir beschlossen, die erste Stufe zu überspringen. In der zweiten Phase mussten mehr als 100 Projekte konvertiert werden. Wie dieser Prozess abläuft, erfahren Sie hier im Detail.


Wir haben verstanden, dass Automatisierung nicht vermieden werden kann. Verwendete die fertige Lösung: CsprojToVs2017 . Lassen Sie sich vom Projektnamen nicht stören: Das Dienstprogramm konvertiert auch für Visual Studio 2019.



Was wird passieren?


Die Größe der csproj-Dateien nimmt ab. Aufgrund was? Alle verbundenen Dateien mit Quellcode verlassen csproj, zusätzliche Zeilen werden entfernt usw.



- <Compile Include="Models\ViewModels\HistoryViewModel.cs" /> - <Compile Include="Properties\Settings.Designer.cs"> - <AutoGen>True</AutoGen> - <DependentUpon>Settings.settings</DependentUpon> - <DesignTimeSharedInput>True</DesignTimeSharedInput> - </Compile> 


Verbundene Bibliotheks- und Teilprojekteinträge werden reduziert.



 - <Reference Include="NLog, Version=4.0.0.0, Culture=neutral, PublicKeyToken=5120e14c03d0593c, processorArchitecture=MSIL"> - <HintPath>..\packages\NLog.4.3.3\lib\net45\NLog.dll</HintPath> - <Private>False</Private> - </Reference> - <ProjectReference Include="..\WpfCommon\WpfCommon.csproj"> - <Project>{7ce118f6-2978-42a7-9e6a-ee5cd3057e29}</Project> - <Name>WpfCommon</Name> - </ProjectReference> + <PackageReference Include="NLog" Version="4.6.7" /> + <ProjectReference Include="..\WpfCommon\WpfCommon.csproj" /> 


Die allgemeinen Einstellungen für mehrere Projekte können in Directory.BuildProps vorgenommen werden. Dies ist eine so spezielle Datei, die MsBuild untersucht.
In Analogie zu .gitignore und .editorconfig haben wir eine globale Datei mit allgemeinen Einstellungen.
Wir fügen die privaten PropertyGroup-Einstellungen für Unterverzeichnisse / Projekte bestimmten csproj-Dateien hinzu. Details finden Sie hier.



Abhängigkeiten



Alte Abhängigkeiten gelten für netframework. Sie müssen eine Alternative oder ähnliche Pakete für Nuget finden. Für viele Projekte gibt es bereits ein Nuget-Paket, das Netcore oder Netstandard unterstützt.



Das Projekt verwendete beispielsweise eine alte Version von DI Unity. Beim Wechsel zu einer neuen Version musste ich den Code an zwei oder drei Stellen aktualisieren und korrigieren.


 using Microsoft.Practices.Unity -> using Unity; 


Und vielleicht reicht es aus, alle Versionen von Paketen zu aktualisieren. Und für alle Fälle starten Sie das Studio neu.



Ändern Sie csproj, um netcore zu verwenden



In Projekten, die WPF-Steuerelemente verwenden, müssen Sie das Format in Microsoft.NET.Sdk.WindowsDesktop ändern:



 -<?xml version="1.0" encoding="utf-8"?> -<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> - <Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" /> - <PropertyGroup/> 

 +<Project Sdk="Microsoft.NET.Sdk.WindowsDesktop"> + <PropertyGroup> + <TargetFramework>netcoreapp3.0</TargetFramework> + <AssemblyTitle>MyEnterpriseLibrary</AssemblyTitle> + <Product>MyEnterpriseLibrary</Product> + <OutputPath>..\bin\$(Configuration)\</OutputPath> + <UseWPF>true</UseWPF> + <!--    assemblyinfo    ,    --> + <GenerateAssemblyInfo>false</GenerateAssemblyInfo> </Project> 


Lassen Sie für ClassLibrary einfach den Microsoft.NET.Sdk-Typ:



 <Project Sdk="Microsoft.NET.Sdk"> <PropertyGroup> <TargetFramework>netcoreapp3.0</TargetFramework> <AssemblyTitle>MyEnterpriseLibrary</AssemblyTitle> <Product>MyEnterpriseLibrary</Product> <OutputPath>..\bin\$(Configuration)\</OutputPath> </PropertyGroup> <!-- ... --> </Project> 


In einigen Projekten, die die Windows Forms-Steuerelemente verwenden, müssen Sie möglicherweise auch UseWindowsForms aufrufen:


 <UseWindowsForms>true</UseWindowsForms> 


Csproj hat seinen Ansatz für den Ablauf der Ressourcenkompilierung geändert. Bisher konnten Sie mit dem Format die Datei sowohl mit Ressourcen als auch mit Inhalten verbinden.
und sogar wo.


Wenn sich die Datei in einer Sammlung befindet, müssen Sie sie entfernen und erst dann in die gewünschte Gruppe aufnehmen.
Hier ist der Code, der file.json aus der None-Auflistung abruft und mit der Resource-Auflistung verbindet.



 <ItemGroup> <None Exclude="file.json" /> <Resource Include="file.json" /> </ItemGroup> 


Dementsprechend müssen alle Dateien, die keine Quelldateien sind, aus der Auflistung None entfernt und mit Ressourcen verbunden werden. Zum Beispiel so:



 <ItemGroup Condition="'$(UseWPF)' == 'true' And $(UseWindowsForms) != 'true'"> <None Exclude="**\*.xml;**\*.xsl;**\*.xslt;**\*.txt;**\*.bmp;**\*.ico;**\*.cur;**\*.gif;**\*.jpeg;**\*.jpe;**\*.jpg;**\*.png;**\*.dib;**\*.tiff;**\*.tif;**\*.inf;**\*.compositefont;**\*.otf;**\*.ttf;**\*.ttc;**\*.tte" /> <Resource Include="**\*.xml;**\*.xsl;**\*.xslt;**\*.txt;**\*.bmp;**\*.ico;**\*.cur;**\*.gif;**\*.jpeg;**\*.jpe;**\*.jpg;**\*.png;**\*.dib;**\*.tiff;**\*.tif;**\*.inf;**\*.compositefont;**\*.otf;**\*.ttf;**\*.ttc;**\*.tte" /> </ItemGroup> 


Einige Zeilen müssen gelöscht werden, da sie die Framework-Version unter .net Framework 4.0 deaktivieren.



  Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" 


An einigen Stellen nach der Konvertierung bleiben seltsame Einträge übrig, die das Kompilieren des Projekts verhindern. Hier sind Beispiele für solche Konstruktionen:



 - <ItemGroup> - <EmbeddedResource Include="**\*.resx" /> - </ItemGroup> - <Compile Remove="something.cs"> 


WCF-Clients



Wenn Sie WCF verwendet haben, müssen Sie die Bindungen neu generieren. Wie dies richtig gemacht wird, finden Sie hier: docs.microsoft.com/en-us/dotnet/desktop-wpf/migration/convert-project-from-net-framework#updating-wcf-client-usage



Was hebt nicht ab?



Stylecop- und Code-Analyse.



Einige unserer Projekte verwendeten statische Code-Analysatoren. Beim Wechsel zu modernen MsBuild-Editionen schlägt der Kollektor ausdrücklich vor, anstelle der alten statischen Code-Analysatoren neue Roslyn-Analysatoren zu verwenden.



Ich musste die alten Regeln übersetzen, um die Nuget-Pakete Stylecop.Analyzers und FxCop.Analyzers gemäß diesem Microsoft-Handbuch zu verwenden. .
Wenn Sie mehrere Projekte in verschiedenen Ordnern haben (Mono-Repository), ist es viel bequemer, die Verbindung von Analysatoren in Build.props zu löschen und sie mit einem einheitlichen Regelsatz zu konfigurieren.



Folgendes ist passiert:



 - <RunCodeAnalysis>true</RunCodeAnalysis> + <PackageReference Include="FxCop.Analyzers" Version="2.9.4" /> 


Dateien - Waisen



Das alte csproj-Format implizierte eine explizite Verbindung von CS-Dateien. Gleichzeitig wurden manchmal beim Umbenennen oder Umgestalten alter Dateien aus csproj gelöscht, jedoch nicht explizit aus dem Dateisystem. Im neuen csproj-Format werden alle Dateien, die sich im Projektordner befinden, automatisch übernommen, nur diejenigen, die zuvor noch nicht gelöscht wurden. Höchstwahrscheinlich werden Fehler darin enthalten sein, die sich auf bereits nicht vorhandene Klassen, Methoden und Ressourcen beziehen. Dies führt zu häufigen Fehlern bei der Montage.



Ressourcen



In einem der Projekte wurde SplashScreen verwendet, von denen eines beim Start zufällig ausgewählt wurde. Die SplashScreen-Instanz wurde mit dem Pfad zur Ressource initialisiert. Aus irgendeinem Grund war es nicht möglich, bei Netcore 3 zu gewinnen: schwört auf das Fehlen einer Ressource.



Code, der zu funktionieren scheint



Code, der im .Net Framework funktioniert hat, funktioniert wahrscheinlich auch in Netcore. Es kann jedoch Codeabschnitte geben, für die der Compiler die Augen geschlossen hat. In diesem Fall wird PlatformException abgefangen, wenn der Code Anweisungen erhält, die nicht in Netcore implementiert sind.


Um nach solchen Orten zu suchen, gibt es einen speziellen Analysator: github.com/dotnet/platform-compat .



Warum das alles, wenn das Projekt funktioniert?



Es gibt nicht viele Vorteile, aber sie sind es dennoch.



  • Ihr Code erhält alle Optimierungen, die zu netcore hinzugefügt wurden.
  • Die Startgeschwindigkeit der Anwendung wird erhöht.
  • Targeting zukünftiger Versionen von C #.
  • Reduzierte Bauzeit für Projekte dank neuer Versionen von csproj.
  • Verpackung in Single Exe.


Microsoft stellt die Anwendung nicht auf eine neue Grundlage. Wenn Ihre Anwendung jedoch ein Plugin eines anderen größeren ist, ist es sinnvoll, auf zukünftige Versionen zu zielen, die möglicherweise auch auf Netcore verfügbar sind.



Nützliche Links



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


All Articles