Migrate from Newtonsoft.Json to System.Text.Json

This commit is contained in:
ChsBuffer
2021-03-01 16:39:11 +08:00
parent 74aa072d9b
commit 5225a98581
20 changed files with 158 additions and 141 deletions

View File

@@ -2,11 +2,11 @@
using System.Collections.Generic;
using System.IO;
using System.Net;
using System.Text.Json;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using Netch.Models.GitHubRelease;
using Netch.Utils;
using Newtonsoft.Json;
using static Netch.Updater.Updater;
namespace Netch.Controllers
@@ -43,7 +43,7 @@ namespace Netch.Controllers
var json = await WebUtil.DownloadStringAsync(WebUtil.CreateRequest(url));
var releases = JsonConvert.DeserializeObject<List<Release>>(json);
var releases = JsonSerializer.Deserialize<List<Release>>(json);
LatestRelease = VersionUtil.GetLatestRelease(releases, isPreRelease);
LatestVersionNumber = LatestRelease.tag_name;
LatestVersionUrl = LatestRelease.html_url;

View File

@@ -729,14 +729,16 @@ namespace Netch.Forms
private void EditServerPictureBox_Click(object sender, EventArgs e)
{
// 当前ServerComboBox中至少有一项
if (ServerComboBox.SelectedIndex == -1)
if (!(ServerComboBox.SelectedItem is Server server))
{
MessageBoxX.Show(i18N.Translate("Please select a server first"));
return;
}
if (!server.Valid())
return;
Hide();
var server = Global.Settings.Server[ServerComboBox.SelectedIndex];
ServerHelper.GetUtilByTypeName(server.Type).Edit(server);
LoadServers();
Configuration.Save();
@@ -774,16 +776,18 @@ namespace Netch.Forms
private void CopyLinkPictureBox_Click(object sender, EventArgs e)
{
// 当前ServerComboBox中至少有一项
if (ServerComboBox.SelectedIndex == -1)
if (!(ServerComboBox.SelectedItem is Server server))
{
MessageBoxX.Show(i18N.Translate("Please select a server first"));
return;
}
if (!server.Valid())
return;
try
{
//听说巨硬BUG经常会炸所以Catch一下 :D
var server = (Server) ServerComboBox.SelectedItem;
string text;
if (ModifierKeys == Keys.Control)
text = ShareLink.GetNetchLink(server);

View File

@@ -4,6 +4,8 @@ using System.Linq;
using System.Net;
using System.Net.NetworkInformation;
using System.Net.Sockets;
using System.Text.Encodings.Web;
using System.Text.Json;
using System.Threading;
using System.Windows.Forms;
using WindowsJobAPI;
@@ -114,5 +116,12 @@ namespace Netch
/// 主窗体的静态实例
/// </summary>
public static MainForm MainForm => _mainForm ??= new MainForm();
public static JsonSerializerOptions NewDefaultJsonSerializerOptions => new()
{
WriteIndented = true,
IgnoreNullValues = true,
Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping
};
}
}

View File

@@ -1,6 +1,6 @@
using System.Collections.Generic;
using System;
using System.Collections.Generic;
using Netch.Controllers;
using Newtonsoft.Json.Linq;
namespace Netch.Models
{
@@ -28,7 +28,7 @@ namespace Netch.Models
/// </summary>
string[] UriScheme { get; }
Server ParseJObject(in JObject j);
public abstract Type ServerType { get; }
public void Edit(Server s);

View File

@@ -43,9 +43,9 @@
<PackageReference Include="MaxMind.GeoIP2" Version="4.0.1" />
<PackageReference Include="Microsoft.Diagnostics.Tracing.TraceEvent" Version="2.0.66" GeneratePathProperty="true" />
<PackageReference Include="Microsoft.Win32.Registry" Version="5.0.0" />
<PackageReference Include="Newtonsoft.Json" Version="12.0.3" />
<PackageReference Include="System.Collections.Immutable" Version="5.0.0" />
<PackageReference Include="System.Reflection.Metadata" Version="5.0.0" />
<PackageReference Include="System.Text.Json" Version="5.0.1"/>
<PackageReference Include="TaskScheduler" Version="2.9.1" />
<PackageReference Include="Vanara.PInvoke.IpHlpApi" Version="3.3.4" />
<PackageReference Include="Microsoft-WindowsAPICodePack-Shell" Version="1.1.4" />

View File

@@ -1,6 +1,7 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text.Json;
using System.Text.RegularExpressions;
using System.Web;
using Netch.Controllers;
@@ -8,8 +9,6 @@ using Netch.Models;
using Netch.Servers.Shadowsocks.Form;
using Netch.Servers.Shadowsocks.Models.SSD;
using Netch.Utils;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
namespace Netch.Servers.Shadowsocks
{
@@ -25,10 +24,7 @@ namespace Netch.Servers.Shadowsocks
public string[] UriScheme { get; } = {"ss", "ssd"};
public Server ParseJObject(in JObject j)
{
return j.ToObject<Shadowsocks>();
}
public Type ServerType { get; } = typeof(Shadowsocks);
public void Edit(Server s)
{
@@ -80,7 +76,7 @@ namespace Netch.Servers.Shadowsocks
public IEnumerable<Server> ParseSsdUri(string s)
{
var json = JsonConvert.DeserializeObject<Main>(ShareLink.URLSafeBase64Decode(s.Substring(6)));
var json = JsonSerializer.Deserialize<Main>(ShareLink.URLSafeBase64Decode(s.Substring(6)));
return json.servers.Select(server => new Shadowsocks
{

View File

@@ -6,7 +6,6 @@ using Netch.Models;
using Netch.Servers.Shadowsocks;
using Netch.Servers.ShadowsocksR.Form;
using Netch.Utils;
using Newtonsoft.Json.Linq;
namespace Netch.Servers.ShadowsocksR
{
@@ -22,10 +21,7 @@ namespace Netch.Servers.ShadowsocksR
public string[] UriScheme { get; } = {"ssr"};
public Server ParseJObject(in JObject j)
{
return j.ToObject<ShadowsocksR>();
}
public Type ServerType { get; } = typeof(ShadowsocksR);
public void Edit(Server s)
{

View File

@@ -4,7 +4,6 @@ using System.Linq;
using Netch.Controllers;
using Netch.Models;
using Netch.Servers.Socks5.Form;
using Newtonsoft.Json.Linq;
namespace Netch.Servers.Socks5
{
@@ -20,10 +19,7 @@ namespace Netch.Servers.Socks5
public string[] UriScheme { get; } = { };
public Server ParseJObject(in JObject j)
{
return j.ToObject<Socks5>();
}
public Type ServerType { get; } = typeof(Socks5);
public void Edit(Server s)
{

View File

@@ -1,9 +1,9 @@
using System.Collections.Generic;
using System.IO;
using System.Text.Json;
using Netch.Controllers;
using Netch.Models;
using Netch.Servers.Trojan.Models;
using Newtonsoft.Json;
namespace Netch.Servers.Trojan
{
@@ -39,13 +39,7 @@ namespace Netch.Servers.Trojan
if (!string.IsNullOrWhiteSpace(server.Host))
trojanConfig.ssl.sni = server.Host;
File.WriteAllText("data\\last.json",
JsonConvert.SerializeObject(trojanConfig,
Formatting.Indented,
new JsonSerializerSettings
{
NullValueHandling = NullValueHandling.Ignore
}));
JsonSerializer.SerializeAsync(File.Create("data\\last.json"), trojanConfig, Global.NewDefaultJsonSerializerOptions);
StartInstanceAuto("-c ..\\data\\last.json");
}

View File

@@ -5,7 +5,6 @@ using System.Web;
using Netch.Controllers;
using Netch.Models;
using Netch.Servers.Trojan.Form;
using Newtonsoft.Json.Linq;
namespace Netch.Servers.Trojan
{
@@ -21,10 +20,7 @@ namespace Netch.Servers.Trojan
public string[] UriScheme { get; } = {"trojan"};
public Server ParseJObject(in JObject j)
{
return j.ToObject<Trojan>();
}
public Type ServerType { get; } = typeof(Trojan);
public void Edit(Server s)
{

View File

@@ -1,8 +1,8 @@
using System.Collections.Generic;
using System.Linq;
using System.Text.Json;
using Netch.Models;
using Netch.Servers.V2ray.Models;
using Newtonsoft.Json;
using V2rayConfig = Netch.Servers.V2ray.Models.V2rayConfig;
namespace Netch.Servers.V2ray.Utils
@@ -19,9 +19,7 @@ namespace Netch.Servers.V2ray.Utils
outbound(server, mode, ref v2rayConfig);
return JsonConvert.SerializeObject(v2rayConfig,
Formatting.Indented,
new JsonSerializerSettings {NullValueHandling = NullValueHandling.Ignore});
return JsonSerializer.Serialize(v2rayConfig, Global.NewDefaultJsonSerializerOptions);
}
private static void inbound(Server server, ref V2rayConfig v2rayConfig)

View File

@@ -1,8 +1,8 @@
using System;
using System.Collections.Generic;
using Netch.Controllers;
using Netch.Models;
using Netch.Servers.V2ray;
using Newtonsoft.Json.Linq;
namespace Netch.Servers.VLESS
{
@@ -18,10 +18,7 @@ namespace Netch.Servers.VLESS
public string[] UriScheme { get; } = {"vless"};
public Server ParseJObject(in JObject j)
{
return j.ToObject<VLESS>();
}
public Type ServerType { get; } = typeof(VLESS);
public void Edit(Server s)
{

View File

@@ -1,12 +1,13 @@
using System;
using System.Collections.Generic;
using System.Text.Encodings.Web;
using System.Text.Json;
using Netch.Controllers;
using Netch.Models;
using Netch.Servers.V2ray;
using Netch.Servers.V2ray.Models;
using Netch.Servers.VMess.Form;
using Netch.Utils;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
namespace Netch.Servers.VMess
{
@@ -22,10 +23,7 @@ namespace Netch.Servers.VMess
public string[] UriScheme { get; } = {"vmess"};
public Server ParseJObject(in JObject j)
{
return j.ToObject<VMess>();
}
public Type ServerType { get; } = typeof(VMess);
public void Edit(Server s)
{
@@ -43,20 +41,24 @@ namespace Netch.Servers.VMess
{
var server = (VMess) s;
var vmessJson = JsonConvert.SerializeObject(new
{
v = "2",
ps = server.Remark,
add = server.Hostname,
port = server.Port,
id = server.UserID,
aid = server.AlterID,
net = server.TransferProtocol,
type = server.FakeType,
host = server.Host,
path = server.Path,
tls = server.TLSSecureType
});
var vmessJson = JsonSerializer.Serialize(new V2rayNSharing
{
v = "2",
ps = server.Remark,
add = server.Hostname,
port = server.Port.ToString(),
id = server.UserID,
aid = server.AlterID.ToString(),
net = server.TransferProtocol,
type = server.FakeType,
host = server.Host,
path = server.Path,
tls = server.TLSSecureType
},
new JsonSerializerOptions
{
Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping
});
return "vmess://" + ShareLink.URLSafeBase64Encode(vmessJson);
}
@@ -76,7 +78,7 @@ namespace Netch.Servers.VMess
V2rayNSharing vmess;
try
{
vmess = JsonConvert.DeserializeObject<V2rayNSharing>(ShareLink.URLSafeBase64Decode(text.Substring(8)));
vmess = JsonSerializer.Deserialize<V2rayNSharing>(ShareLink.URLSafeBase64Decode(text.Substring(8)));
}
catch
{

View File

@@ -1,8 +1,8 @@
using System.IO;
using System;
using System.IO;
using System.Linq;
using System.Text.Json;
using Netch.Models;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
namespace Netch.Utils
{
@@ -23,30 +23,9 @@ namespace Netch.Utils
/// </summary>
public static void Load()
{
if (Directory.Exists(DATA_DIR) && File.Exists(SETTINGS_JSON))
if (File.Exists(SETTINGS_JSON))
{
try
{
var settingJObject = (JObject) JsonConvert.DeserializeObject(File.ReadAllText(SETTINGS_JSON))!;
Global.Settings = settingJObject?.ToObject<Setting>() ?? new Setting();
Global.Settings.Server.Clear();
if (settingJObject?["Server"] != null)
foreach (JObject server in settingJObject["Server"]!)
{
var serverResult = ServerHelper.ParseJObject(server);
if (serverResult != null)
Global.Settings.Server.Add(serverResult);
}
if (settingJObject?["Profiles"] != null && Global.Settings.Profiles.Any() &&
settingJObject["Profiles"]!.First()?["Index"] == null)
foreach (var profile in Global.Settings.Profiles)
profile.Index = Global.Settings.Profiles.IndexOf(profile);
}
catch (JsonException)
{
}
Global.Settings = ParseSetting(File.ReadAllText(SETTINGS_JSON));
}
else
{
@@ -58,6 +37,34 @@ namespace Netch.Utils
}
}
public static Setting ParseSetting(string text)
{
try
{
var jsonSerializerOptions = Global.NewDefaultJsonSerializerOptions;
jsonSerializerOptions.Converters.Add(new ServerConverterWithTypeDiscriminator());
var settings = JsonSerializer.Deserialize<Setting>(text, jsonSerializerOptions)!;
#region Check Profile
foreach (var profile in settings.Profiles.Where(p => p.ServerRemark == string.Empty || p.ModeRemark == string.Empty)!)
settings.Profiles.Remove(profile);
if (settings.Profiles.Any(p => settings.Profiles.Any(p1 => p1 != p && p1.Index == p.Index)))
for (var i = 0; i < settings.Profiles.Count; i++)
settings.Profiles[i].Index = i;
#endregion
return settings;
}
catch (Exception e)
{
Logging.Error(e.ToString());
return new Setting();
}
}
/// <summary>
/// 保存配置
/// </summary>
@@ -66,13 +73,7 @@ namespace Netch.Utils
if (!Directory.Exists(DATA_DIR))
Directory.CreateDirectory(DATA_DIR);
File.WriteAllText(SETTINGS_JSON,
JsonConvert.SerializeObject(Global.Settings,
Formatting.Indented,
new JsonSerializerSettings
{
NullValueHandling = NullValueHandling.Ignore
}));
File.WriteAllBytes(SETTINGS_JSON, JsonSerializer.SerializeToUtf8Bytes(Global.Settings, Global.NewDefaultJsonSerializerOptions));
}
}
}

View File

@@ -0,0 +1,32 @@
using System;
using System.Text.Json;
using System.Text.Json.Serialization;
using Netch.Models;
namespace Netch.Utils
{
public class ServerConverterWithTypeDiscriminator : JsonConverter<Server>
{
public override bool CanConvert(Type typeToConvert) => typeToConvert == typeof(Server);
public override Server Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
var jsonElement = JsonSerializer.Deserialize<JsonElement>(ref reader)!;
try
{
var type = ServerHelper.GetTypeByTypeName(jsonElement.GetProperty("Type").GetString()!);
return (Server) JsonSerializer.Deserialize(jsonElement.GetRawText(), type)!;
}
catch
{
return JsonSerializer.Deserialize<Server>(jsonElement.GetRawText(), new JsonSerializerOptions())!;
}
}
public override void Write(Utf8JsonWriter writer, Server value, JsonSerializerOptions options)
{
JsonSerializer.Serialize(writer, value, options);
}
}
}

View File

@@ -5,7 +5,6 @@ using System.Reflection;
using System.Threading.Tasks;
using System.Timers;
using Netch.Models;
using Newtonsoft.Json.Linq;
namespace Netch.Utils
{
@@ -20,6 +19,11 @@ namespace Netch.Utils
ServerUtils = serversUtilsTypes.Select(t => (IServerUtil) Activator.CreateInstance(t)).OrderBy(util => util.Priority);
}
public static Type GetTypeByTypeName(string typeName)
{
return ServerUtils.Single(i => i.TypeName.Equals(typeName)).ServerType;
}
#region Delay
public static class DelayTestHelper
@@ -98,22 +102,6 @@ namespace Netch.Utils
public static readonly IEnumerable<IServerUtil> ServerUtils;
public static Server? ParseJObject(JObject o)
{
try
{
var type = (string) o["Type"]!;
var handle = GetUtilByTypeName(type);
return handle.ParseJObject(o);
}
catch (Exception e)
{
Console.WriteLine($"读取服务器错误: {e}\n错误项: {o}");
return null;
}
}
public static IServerUtil GetUtilByTypeName(string typeName)
{
if (string.IsNullOrEmpty(typeName))

View File

@@ -3,11 +3,10 @@ using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Text.Json;
using Netch.Models;
using Netch.Servers.Shadowsocks;
using Netch.Servers.Shadowsocks.Models;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
namespace Netch.Utils
{
@@ -33,7 +32,7 @@ namespace Netch.Utils
try
{
list.AddRange(JsonConvert.DeserializeObject<List<ShadowsocksConfig>>(text)
list.AddRange(JsonSerializer.Deserialize<List<ShadowsocksConfig>>(text)
.Select(server => new Shadowsocks
{
Hostname = server.server,
@@ -45,7 +44,7 @@ namespace Netch.Utils
PluginOption = server.plugin_opts
}));
}
catch (JsonReaderException)
catch (JsonException)
{
foreach (var line in text.GetLines())
list.AddRange(ParseUri(line));
@@ -105,21 +104,28 @@ namespace Netch.Utils
private static Server ParseNetchUri(string text)
{
text = text.Substring(8);
text = URLSafeBase64Decode(text.Substring(8));
var jObject = (JObject) JsonConvert.DeserializeObject(URLSafeBase64Decode(text))!;
var NetchLink = JsonSerializer.Deserialize<JsonElement>(text);
var type = (string) jObject["Type"]!;
var s = ServerHelper.GetUtilByTypeName(type).ParseJObject(jObject);
return ServerHelper.GetUtilByTypeName(s.Type).CheckServer(s) ? s : throw new FormatException();
if (string.IsNullOrEmpty(NetchLink.GetProperty("Hostname").GetString()))
throw new FormatException();
if (!ushort.TryParse(NetchLink.GetProperty("Port").GetString(), out _))
throw new FormatException();
return JsonSerializer.Deserialize<Server>(text,
new JsonSerializerOptions
{
Converters = {new ServerConverterWithTypeDiscriminator()}
})!;
}
public static string GetNetchLink(Server s)
{
var server = (Server) s.Clone();
return "Netch://" +
URLSafeBase64Encode(JsonConvert.SerializeObject(server,
new JsonSerializerSettings {NullValueHandling = NullValueHandling.Ignore}));
var jsonSerializerOptions = Global.NewDefaultJsonSerializerOptions;
jsonSerializerOptions.WriteIndented = false;
return "Netch://" + URLSafeBase64Encode(JsonSerializer.Serialize(s, jsonSerializerOptions));
}
#region Utils

View File

@@ -4,9 +4,9 @@ using System.Globalization;
using System.IO;
using System.Linq;
using System.Text;
using System.Text.Json;
using System.Windows.Forms;
using Netch.Properties;
using Newtonsoft.Json;
namespace Netch.Utils
{
@@ -57,7 +57,7 @@ namespace Netch.Utils
break;
}
var dictionary = JsonConvert.DeserializeObject<Dictionary<string, string>>(text);
var dictionary = JsonSerializer.Deserialize<Dictionary<string, string>>(text);
if (!dictionary.Any())
{

View File

@@ -1,14 +1,14 @@
using Netch;
using Newtonsoft.Json;
using System.Text.Json;
using Netch;
namespace UnitTest
{
public class TestBase
{
private readonly JsonSerializerSettings _serializerSettings = new()
private readonly JsonSerializerOptions _serializerSettings = new()
{
Formatting = Formatting.Indented,
NullValueHandling = NullValueHandling.Ignore
WriteIndented = true,
IgnoreNullValues = true
};
protected TestBase()
@@ -20,7 +20,7 @@ namespace UnitTest
protected string JsonSerializerFormatted(object o)
{
return JsonConvert.SerializeObject(o, _serializerSettings);
return JsonSerializer.Serialize(o, _serializerSettings);
}
}
}

View File

@@ -5,6 +5,7 @@
<Platforms>x64</Platforms>
<UseWindowsForms>true</UseWindowsForms>
<LangVersion>latest</LangVersion>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
</PropertyGroup>
<ItemGroup>
@@ -24,6 +25,7 @@
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.9.1"/>
<PackageReference Include="MSTest.TestAdapter" Version="2.1.2"/>
<PackageReference Include="MSTest.TestFramework" Version="2.1.2"/>
<PackageReference Include="System.Text.Json" Version="5.0.1"/>
</ItemGroup>
</Project>