WPF项目从.Net Framework迁移到.Net6
2023-06-13 09:13:29 时间
前言
先决条件
- Windows 操作系统
- .NET 6 SDK
- Visual Studio 2022 17.0 或更高版本
.NET 升级助手是一个 .NET 工具,可以使用以下命令进行全局安装:
dotnet tool install -g upgrade-assistant
运行
upgrade-assistant upgrade .\SchoolClient.sln
目前结论
老项目依赖众多,很多依赖并不支持.net6,因此放弃迁移。 新项目可以考虑使用。
问题处理
打印不显示
打印要替换为
System.Diagnostics.Trace.WriteLine("WS:用户上线");
依赖不兼容
自动迁移后的包
我们发现自动迁移后有些包是不可用的。
<ItemGroup>
<PackageReference Include="Aspose.Words" Version="19.10.0" />
<PackageReference Include="ICSharpCode.SharpZipLib.dll" Version="0.85.4.369" />
<PackageReference Include="ImageProcessor" Version="2.9.1" />
<PackageReference Include="Imazen.WebP" Version="10.0.1" />
<PackageReference Include="LiveCharts.Wpf" Version="0.9.7" />
<PackageReference Include="Microsoft.AspNet.WebApi.Client" Version="5.2.9" />
<PackageReference Include="Microsoft.Office.Interop.Word" Version="15.0.4797.1004" />
<PackageReference Include="Newtonsoft.Json" Version="12.0.3" />
<PackageReference Include="QRCoder" Version="1.3.9" />
<PackageReference Include="SuperWebSocket" Version="0.9.0.2" />
<PackageReference Include="System.ComponentModel.Annotations" Version="5.0.0" />
<PackageReference Include="System.Data.DataSetExtensions" Version="4.5.0" />
<PackageReference Include="System.Data.SQLite" Version="1.0.113.7" />
<PackageReference Include="WpfAnimatedGif" Version="2.0.0" />
<PackageReference Include="System.ServiceModel.Federation" Version="4.8.1" />
<PackageReference Include="Microsoft.DotNet.UpgradeAssistant.Extensions.Default.Analyzers" Version="0.4.336902">
<PrivateAssets>all</PrivateAssets>
</PackageReference>
<PackageReference Include="Microsoft.Windows.Compatibility" Version="6.0.0" />
</ItemGroup>
发现很多库不支持.net core
要找对应支持的版本进行替换
更换后的包
<ItemGroup>
<PackageReference Include="Aspose.Words" Version="19.10.0" />
<PackageReference Include="ImageProcessor.Core" Version="1.1.0" />
<PackageReference Include="LiveCharts.Wpf.Core" Version="0.9.8" />
<PackageReference Include="log4net" Version="2.0.15" />
<PackageReference Include="Microsoft.AspNet.WebApi.Client" Version="5.2.9" />
<PackageReference Include="Microsoft.Extensions.Configuration" Version="6.0.1" />
<PackageReference Include="Microsoft.Office.Interop.Word" Version="15.0.4797.1004" />
<PackageReference Include="Newtonsoft.Json" Version="12.0.3" />
<PackageReference Include="QRCoder" Version="1.3.9" />
<PackageReference Include="SharpZipLib" Version="1.3.3" />
<PackageReference Include="System.ComponentModel.Annotations" Version="5.0.0" />
<PackageReference Include="System.Data.DataSetExtensions" Version="4.5.0" />
<PackageReference Include="System.Data.SQLite" Version="1.0.113.7" />
<PackageReference Include="TouchSocket" Version="0.5.2" />
<PackageReference Include="WpfAnimatedGif" Version="2.0.0" />
<PackageReference Include="System.ServiceModel.Federation" Version="4.8.1" />
<PackageReference Include="Microsoft.Windows.Compatibility" Version="6.0.0" />
</ItemGroup>
其中有的库要找Core版本的,如
ImageProcessor
=>ImageProcessor.Core
LiveCharts.Wpf
=> LiveCharts.Wpf.Core`.
有的库就要换成新的了
SuperWebSocket
=>TouchSocket
Imazen.WebP
=>https://github.com/psvmc/Imazen.WebP
预生成事件保持不变
xcopy /Y /i /e $(ProjectDir)\wwwroot $(TargetDir)\wwwroot
xcopy /Y /d $(ProjectDir)\DLL\libwebp.dll $(TargetDir)
程序不包含适合于入口点
报错
程序不包含适合于入口点的静态 “Main” 方法
解决方式
生成操作选择 应用程序定义
自定义工具输入 MSBuild:Compile
appSettings读写
.net framework的读写方式
以前配置在App.config
中的appSettings
下
之前的读写方法
/// <summary>
/// 配置文件读取
/// </summary>
/// <param name="key">配置文件中key字符串</param>
/// <returns></returns>
public static string GetConfigValue(string key)
{
try
{
Configuration config = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);
//获取AppSettings的节点
AppSettingsSection appsection = (AppSettingsSection)config.GetSection("appSettings");
return appsection.Settings[key].Value;
}
catch
{
return "";
}
}
/// <summary>
/// 配置文件写入
/// </summary>
/// <param name="key">配置文件中key字符串</param>
/// <param name="value">配置文件中value字符串</param>
/// <returns></returns>
public static bool SetConfigValue(string key, string value)
{
try
{
//打开配置文件
Configuration config = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);
//获取AppSettings的节点
AppSettingsSection appsection = (AppSettingsSection)config.GetSection("appSettings");
appsection.Settings[key].Value = value;
config.Save();
return true;
}
catch
{
return false;
}
}
迁移后就不能用了,原来的配置文件变成了
相应的读写方法也变了。
.net6读取appsettings.json
Nuget 安装 Microsoft.Extensions.Configuration
using Microsoft.Extensions.Configuration;
using System.Linq;
namespace SchoolClient.Utils
{
public class ZConfigCoreUtil
{
private static IConfiguration _config;
public static void init()
{
_config = new ConfigurationBuilder().AddJsonFile("appsettings.json").Build();
}
/// <summary>
/// 读取指定节点的字符串
/// </summary>
/// <param name="sessions"></param>
/// <returns></returns>
public static string GetVaule(params string[] sessions)
{
if (_config == null)
{
init();
}
try
{
if (sessions.Any())
{
return _config[string.Join(":", sessions)];
}
}
catch
{
return "";
}
return "";
}
public static void test()
{
System.Diagnostics.Trace.WriteLine("IsDebug:" + GetVaule("IsDebug"));
}
}
}
但是只支持读取配置了,不支持写入,所以要把项目运行时读写的字段换一种方式。
其实这也是合理的,我也推荐项目本身的配置和项目运行的配置分开保存,项目的配置只能读取,运行中的配置则可以读写。
下面两种方式任取其一即可。
推荐使用JSON方式。
XML方式读写
using System;
using System.Configuration;
namespace SchoolClient.Utils
{
public static class ZConfigUtil
{
///<summary>
///返回app.config文件中appSettings配置节的value项
///</summary>
///<param name="strKey"></param>
///<returns></returns>
public static string GetVaule(string strKey)
{
return GetVaule(strKey, "app.config");
}
public static string GetVaule(string strKey, string filepath)
{
ExeConfigurationFileMap file = new ExeConfigurationFileMap();
file.ExeConfigFilename = filepath;
Configuration config = ConfigurationManager.OpenMappedExeConfiguration(file, ConfigurationUserLevel.None);
foreach (string key in config.AppSettings.Settings.AllKeys)
{
if (key == strKey)
{
return config.AppSettings.Settings[strKey].Value.ToString();
}
}
return null;
}
///<summary>
///在app.config文件中appSettings配置节增加一对键值对
///</summary>
///<param name="newKey"></param>
///<param name="newValue"></param>
public static void SetVaule(string newKey, string newValue)
{
SetVaule(newKey, newValue, "app.config");
}
public static void SetVaule(string newKey, string newValue, string filepath)
{
ExeConfigurationFileMap file = new ExeConfigurationFileMap();
file.ExeConfigFilename = filepath;
Configuration config = ConfigurationManager.OpenMappedExeConfiguration(file, ConfigurationUserLevel.None);
bool exist = false;
foreach (string key in config.AppSettings.Settings.AllKeys)
{
if (key == newKey)
{
exist = true;
}
}
if (exist)
{
config.AppSettings.Settings.Remove(newKey);
}
config.AppSettings.Settings.Add(newKey, newValue);
config.Save(ConfigurationSaveMode.Modified);
ConfigurationManager.RefreshSection("appSettings");
}
public static void test()
{
SetVaule("ServerIp", "127.0.0.1");
SetVaule("ServerPort", "8899");
Console.WriteLine("ServerIp:" + GetVaule("ServerIp"));
Console.WriteLine("ServerXXX:" + (GetVaule("ServerXXX") == null));
}
}
}
JSON方式读写
using Newtonsoft.Json;
using System;
using System.IO;
namespace SchoolClient.Utils
{
public class ZConfigJsonUtil
{
private static string readtxt(string filepath)
{
string config_txt = "";
using (FileStream fs = new FileStream(filepath, FileMode.OpenOrCreate, FileAccess.ReadWrite))
{
using (StreamReader sr = new StreamReader(fs))
{
config_txt = sr.ReadToEnd();
}
}
return config_txt;
}
private static void writetxt(string filepath, string txt)
{
using (FileStream fs = new FileStream(filepath, FileMode.Truncate, FileAccess.ReadWrite))
{
using (StreamWriter sw = new StreamWriter(fs))
{
sw.Write(txt);
}
}
}
private static string getconfigpath()
{
string docpath = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments);
string configfolderpath = Path.Combine(docpath, "_XHCLASS");
if (!Directory.Exists(configfolderpath))
{
Directory.CreateDirectory(configfolderpath);
}
string configpath = Path.Combine(configfolderpath, "config.json");
return configpath;
}
/// <summary>
/// 初始化配置
/// </summary>
public static void init()
{
string configpath = getconfigpath();
string txt = readtxt(configpath);
if (string.IsNullOrEmpty(txt))
{
txt = "{}";
ConfigModel jsonobj = JsonConvert.DeserializeObject<ConfigModel>(txt);
string docpath = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments);
string configfolderpath = Path.Combine(docpath, "_XHCLASS");
jsonobj.savepath = configfolderpath;
writetxt(configpath, JsonConvert.SerializeObject(jsonobj));
}
}
/// <summary>
/// 获取配置文件
/// </summary>
/// <returns></returns>
public static ConfigModel configGet()
{
string configpath = getconfigpath();
string txt = readtxt(configpath);
if (string.IsNullOrEmpty(txt))
{
txt = "{}";
}
try
{
return JsonConvert.DeserializeObject<ConfigModel>(txt); ;
}
catch (Exception)
{
return new ConfigModel();
}
}
/// <summary>
/// 保存配置文件
/// </summary>
/// <param name="config"></param>
public static void configSet(ConfigModel config)
{
string configpath = getconfigpath();
writetxt(configpath, JsonConvert.SerializeObject(config));
}
/// <summary>
/// 设置临时文件存储位置
/// </summary>
/// <param name="value"></param>
public static void setSavepath(string value)
{
ConfigModel config = configGet();
config.savepath = value;
configSet(config);
}
/// <summary>
/// 获取临时文件存储位置
/// </summary>
/// <returns></returns>
public static string getSavepath()
{
var config = configGet();
if (string.IsNullOrEmpty(config.savepath))
{
string docpath = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments);
string configfolderpath = Path.Combine(docpath, "_XHCLASS");
return configfolderpath;
}
else
{
return config.savepath;
}
}
}
public class ConfigModel
{
public string savepath { get; set; }
}
}
输出精简
多运行时精简
输出目录中创建了一个名为runtime
的文件夹,里面有很多与平台相关的dll。
解决方法
在csproj文件中的PropertyGroup
中,将SelfContained
属性设置为false
并指定一个RuntimeIdentifier
;
如下所示:
<PropertyGroup>
<SelfContained>false</SelfContained>
<RuntimeIdentifier>win-x86</RuntimeIdentifier>
</PropertyGroup>
64位的
<PropertyGroup>
<SelfContained>false</SelfContained>
<RuntimeIdentifier>win-x64</RuntimeIdentifier>
</PropertyGroup>
多语言精简
我们没有为项目指定语言, 所以会列出多种语言。
解决方法:
在csproj文件中的PropertyGroup
中,
<PropertyGroup>
<SatelliteResourceLanguages>zh-Hans</SatelliteResourceLanguages>
</PropertyGroup>
相关文章
- WPF MVVM 模式下自写自用的窗口样式
- WPF-visifire Charts 控件去掉水印
- [.NET控件]Telerik RadControls for ASP.NET AJAX 2008 Q1 net 2.0 Web.UI「建议收藏」
- wpf之StackPanel、WrapPanel、WrapPanel之间的关系
- WPF TextBox模仿PasswordBox的密码显示功能
- 【愚公系列】2022年10月 基于WPF的智能制造MES系统框架-菜单栏的设计
- 【水一篇】骚操作之net 6的winform启动的同时启动Net 6 WebApi【同一套代码】
- .net 温故知新:【8】.NET 中的配置从xml转向json
- OxyPlot.WPF 公共属性一览
- WPF 实现水珠效果按钮组
- WPF 实现带蒙版的 MessageBox 消息提示框
- WPF 已知问题 dotnet 6 设置 InvariantGlobalization 之后将丢失默认绑定转换导致 XAML 抛出异常
- 修复 WPF 安装 WindowsAppSDK 库构建失败 NETSDK1082 和 NETSDK1112 找不到 win10-arm 失败
- WPF 通过 EXIF 设置和读取图片的旋转信息
- Linux.Net:开启新技术之旅(linux.net)
- .NET访问MySQL:简单实用的方法(.net访问mysql)
- 跨平台利器:.NET在Linux上的运行(.net运行在linux)
- .Net搭配Redis解决高性能应用问题(.net redis)
- asp.net的web服务MSSQL检测ASP.NET的Web服务——利用它构建更棒的站点(mssql检测基于)
- WPF连接MySQL:实现跨平台的数据交互(wpf 连接mysql)
- Net访问Oracle数据库的简易方法(.net访问oracle)
- NET与Oracle结合出现新的可能(.net oracle)
- Net环境下MySQL数据库驱动的研究与应用(.net的mysql驱动)
- NET备份MySQL提升数据安全性(.net 备份mysql)
- 网上解决Net环境下MySQL数据库的同步问题(.net 同步mysql)
- NET 对MySQL 的支持有限(.net不支持mysql)
- NET 与 MySQL 结合能实现优雅的数据事务处理(.net MySQL事物)
- asp.net下用Aspose.Wordsfor.NET动态生成word文档中的数据表格的方法
- .Net中导出数据到Excel(asp.net和winform程序中)
- 关于WPF使用MultiConverter控制Button状态的详细介绍