Portage d'applications WPF vers netcore 3.0

La prochaine version de netcore 3.0 vous permet d'exécuter wpf sur netcore. La procédure de traduction d'un projet simple prend un à deux jours. Chaque suivant est beaucoup plus rapide.







Préparation et conversion de projets



La première étape de la préparation consiste à installer et exécuter Portability Analyzer. À la sortie, nous obtenons une plaque Excel dans laquelle nous voyons dans quelle mesure notre code répond aux nouvelles exigences.





La procédure de conversion des anciens projets s'est déroulée en plusieurs étapes.


  1. Microsoft recommande de mettre à niveau la version du framework vers .Net Framework 4.7.3 pour les projets plus anciens.
  2. Convertissez la structure des anciens projets dans un nouveau format. Remplacez packages.config par PackageReference.
  3. Troisièmement, ajustez la structure du fichier csproj au format netcore.


Je tiens à remercier Emil Yangirov pour son rapport sur la migration vers netcore, qui a été très utile. Lien vers son rapport.



Il s'est avéré que nous avons décidé de sauter la première étape. La deuxième étape impliquait la nécessité de convertir plus de 100 projets. Le déroulement de ce processus peut être lu en détail ici .


Nous avons compris que l'automatisation ne pouvait être évitée. Utilisé la solution prête à l' emploi: CsprojToVs2017 . Laissez le nom du projet ne vous dérange pas: l'utilitaire convertit également pour Visual Studio 2019.



Que va-t-il se passer?


La taille des fichiers csproj diminuera. À cause de quoi? Tous les fichiers connectés avec le code source quitteront csproj, les lignes supplémentaires seront supprimées, etc.



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


Les entrées de bibliothèque et de sous-projet connectées seront réduites.



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


Les paramètres généraux de plusieurs projets peuvent être effectués dans Directory.BuildProps. Il s'agit d'un fichier spécial que MsBuild examine.
Par analogie avec .gitignore et .editorconfig, nous avons un fichier global avec les paramètres généraux.
Nous ajoutons les paramètres du PropertyGroup privé pour les sous-répertoires / projets à des fichiers csproj spécifiques. Les détails peuvent être trouvés ici.



Dépendances



Les anciennes dépendances seront pour le netframework. Vous devrez trouver une alternative ou des packages similaires pour nuget. Pour de nombreux projets, il existe déjà un package Nuget qui prend en charge netcore ou netstandard.



Par exemple, le projet a utilisé une ancienne version de DI Unity. Lors du passage à une nouvelle version, j'ai dû mettre à jour en utilisant et corriger le code à deux ou trois endroits.


 using Microsoft.Practices.Unity -> using Unity; 


Et peut-être suffira-t-il de mettre à niveau toutes les versions des packages. Et juste au cas où, redémarrez le studio.



Changer csproj pour utiliser netcore



Dans les projets qui utilisent des contrôles WPF, vous devez modifier le format en Microsoft.NET.Sdk.WindowsDesktop:



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


Pour ClassLibrary, laissez simplement le type Microsoft.NET.Sdk:



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


Peut-être, dans certains projets qui utilisent les contrôles Windows Forms, vous devrez également coller un appel à UseWindowsForms:


 <UseWindowsForms>true</UseWindowsForms> 


Csproj a changé son approche du flux de compilation des ressources. Auparavant, le format vous permettait de connecter le fichier aux ressources et au contenu,
et même où.


Maintenant, si le fichier se trouve dans une sorte de collection, vous devez le supprimer et ensuite l'inclure dans le groupe souhaité.
Voici le code qui extrait file.json de la collection None et le connecte à la collection Resource.



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


Par conséquent, tous les fichiers qui ne sont pas sources doivent être supprimés de la collection None et connectés aux ressources. Par exemple, comme ceci:



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


Certaines lignes devront être supprimées, car elles suppriment la version du framework sur .net framework 4.0.



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


À certains endroits après la conversion, des entrées étranges resteront qui empêcheront le projet de se compiler. Voici des exemples de telles constructions:



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


Clients WCF



Si vous avez utilisé WCF, vous devrez régénérer les liaisons. Comment le faire correctement peut être lu ici: docs.microsoft.com/en-us/dotnet/desktop-wpf/migration/convert-project-from-net-framework#updating-wcf-client-usage



Qu'est-ce qui ne décollera pas?



Stylecop et analyse de code.



Certains de nos projets ont utilisé des analyseurs de code statiques. Lors du passage aux éditions MsBuild modernes, le collecteur suggère explicitement d'utiliser de nouveaux analyseurs Roslyn au lieu des anciens analyseurs de code statique.



J'ai dû traduire les anciennes règles pour utiliser les packages Stylecop.Analyzers et FxCop.Analyzers Nuget en suivant ce guide Microsoft. .
Si vous avez plusieurs projets dans différents dossiers (mono-référentiel), il est beaucoup plus pratique de désactiver la connexion des analyseurs dans Build.props et de les configurer avec un ensemble de règles uniforme.



Voici ce qui s'est passé:



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


Fichiers - Orphelins



L'ancien format csproj impliquait une connexion explicite des fichiers .cs. Dans le même temps, parfois lors du changement de nom ou de la refactorisation d'anciens fichiers étaient supprimés de csproj, mais ils n'étaient pas supprimés explicitement du système de fichiers. Dans le nouveau format csproj, tous les fichiers qui se trouvent dans le dossier du projet seront automatiquement récupérés, uniquement ceux qui n'ont pas été supprimés auparavant. Il y aura très probablement des erreurs, des appels à des classes, des méthodes et des ressources déjà inexistantes. Cela entraînera des erreurs courantes lors de l'assemblage.



Les ressources



Dans l'un des projets, SplashScreen a été utilisé, dont l'un a été sélectionné au hasard au démarrage. L'instance SplashScreen a été initialisée avec le chemin d'accès à la ressource. Pour une raison quelconque, il n'a pas été possible de gagner au netcore 3: ne jure que par le manque de ressources.



Code qui semble fonctionner



Le code qui a fonctionné dans le .Net Framework est également susceptible de fonctionner dans netcore. Mais il peut y avoir des sections de code auxquelles le compilateur a fermé les yeux. Dans ce cas, si le code obtient des instructions qui ne sont pas implémentées dans netcore, nous intercepterons PlatformException.


Afin de rechercher de tels endroits, il existe un analyseur spécial: github.com/dotnet/platform-compat .



Pourquoi tout cela si le projet fonctionne?



Il n'y a pas beaucoup d'avantages, mais néanmoins, ils le sont.



  • Votre code recevra toutes les optimisations ajoutées à netcore.
  • La vitesse de lancement de l'application augmentera.
  • Cibler les futures versions de C #.
  • Temps de construction réduit pour les projets grâce aux nouvelles versions de csproj.
  • Emballage en un seul exe.


Microsoft ne pousse pas l'application sur de nouvelles bases. Néanmoins, si votre application est un plugin d'une autre plus grande, il est logique de viser les futures versions, qui peuvent également être sur netcore.



Liens utiles



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


All Articles