diff --git a/HeadlessExport/App.config b/HeadlessExport/App.config index 5a1f3d40..d0160efe 100644 --- a/HeadlessExport/App.config +++ b/HeadlessExport/App.config @@ -1,13 +1,13 @@  - + - + @@ -17,6 +17,14 @@ + + + + + + + + - \ No newline at end of file + diff --git a/HeadlessExport/HeadlessExport.csproj b/HeadlessExport/HeadlessExport.csproj index e4147401..6acac352 100644 --- a/HeadlessExport/HeadlessExport.csproj +++ b/HeadlessExport/HeadlessExport.csproj @@ -8,10 +8,11 @@ Exe HeadlessExport HeadlessExport - v4.6.1 + v4.8 512 true true + AnyCPU diff --git a/SpellGUIV2/App.config b/SpellGUIV2/App.config index d603b66e..1b8e6804 100644 --- a/SpellGUIV2/App.config +++ b/SpellGUIV2/App.config @@ -5,16 +5,8 @@
- + - - - - - - - - @@ -30,7 +22,7 @@ - + @@ -40,6 +32,20 @@ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/SpellGUIV2/Costura32/SQLite.Interop.dll b/SpellGUIV2/Costura32/SQLite.Interop.dll index 541820ba..716183a1 100644 Binary files a/SpellGUIV2/Costura32/SQLite.Interop.dll and b/SpellGUIV2/Costura32/SQLite.Interop.dll differ diff --git a/SpellGUIV2/Costura64/SQLite.Interop.dll b/SpellGUIV2/Costura64/SQLite.Interop.dll index 0c98886d..fc357b6d 100644 Binary files a/SpellGUIV2/Costura64/SQLite.Interop.dll and b/SpellGUIV2/Costura64/SQLite.Interop.dll differ diff --git a/SpellGUIV2/MainWindow.xaml.cs b/SpellGUIV2/MainWindow.xaml.cs index 1d8ae79e..521ca815 100644 --- a/SpellGUIV2/MainWindow.xaml.cs +++ b/SpellGUIV2/MainWindow.xaml.cs @@ -982,7 +982,7 @@ private async Task GetConfig() Config.Database = db; } } - Config.connectionType = isSqlite ? Config.ConnectionType.SQLite : Config.ConnectionType.MySQL; + Config.connectionType = isSqlite ? Config.ConnectionType.SQLite : /*Config.ConnectionType.MySQL*/Config.ConnectionType.MariaDB; Config.IsInit = true; } } diff --git a/SpellGUIV2/Properties/AssemblyInfo.cs b/SpellGUIV2/Properties/AssemblyInfo.cs index 0970c472..98caba4a 100644 --- a/SpellGUIV2/Properties/AssemblyInfo.cs +++ b/SpellGUIV2/Properties/AssemblyInfo.cs @@ -51,5 +51,5 @@ // You can specify all the values or you can default the Build and Revision Numbers // by using the '*' as shown below: // [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion("2.2.4.0")] -[assembly: AssemblyFileVersion("2.2.4.0")] +[assembly: AssemblyVersion("2.2.4.1")] +[assembly: AssemblyFileVersion("2.2.4.1")] diff --git a/SpellGUIV2/Properties/Resources.Designer.cs b/SpellGUIV2/Properties/Resources.Designer.cs index b478d99c..c7035370 100644 --- a/SpellGUIV2/Properties/Resources.Designer.cs +++ b/SpellGUIV2/Properties/Resources.Designer.cs @@ -19,7 +19,7 @@ namespace SpellEditor.Properties { // class via a tool like ResGen or Visual Studio. // To add or remove a member, edit your .ResX file then rerun ResGen // with the /str option, or rebuild your VS project. - [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "15.0.0.0")] + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "17.0.0.0")] [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] internal class Resources { diff --git a/SpellGUIV2/Properties/Settings.Designer.cs b/SpellGUIV2/Properties/Settings.Designer.cs index 4c0ffb97..cecb25d7 100644 --- a/SpellGUIV2/Properties/Settings.Designer.cs +++ b/SpellGUIV2/Properties/Settings.Designer.cs @@ -12,7 +12,7 @@ namespace SpellEditor.Properties { [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] - [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "15.9.0.0")] + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "17.9.0.0")] internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase { private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings()))); diff --git a/SpellGUIV2/Sources/Config/Config.cs b/SpellGUIV2/Sources/Config/Config.cs index 0d1b8da5..a0329088 100644 --- a/SpellGUIV2/Sources/Config/Config.cs +++ b/SpellGUIV2/Sources/Config/Config.cs @@ -14,7 +14,8 @@ public static class Config public enum ConnectionType { SQLite, - MySQL + MySQL, + MariaDB } public static bool IsInit = false; diff --git a/SpellGUIV2/Sources/Database/AbstractAdapter.cs b/SpellGUIV2/Sources/Database/AbstractAdapter.cs new file mode 100644 index 00000000..6cf99c6d --- /dev/null +++ b/SpellGUIV2/Sources/Database/AbstractAdapter.cs @@ -0,0 +1,101 @@ +using SpellEditor.Sources.Binding; +using System; +using System.Collections.Generic; +using System.Data; +using System.Linq; +using System.Text; + +namespace SpellEditor.Sources.Database +{ + public abstract class AbstractAdapter : IDatabaseAdapter, IDisposable + { + protected readonly object _syncLock = new object(); + public bool Updating { get; set; } + + public List GetAllTableCreateStrings() + { + var list = new List(); + foreach (var binding in BindingManager.GetInstance().GetAllBindings()) + { + list.Add(string.Format(GetTableCreateString(binding), binding.Name.ToLower())); + } + return list; + } + + public virtual string GetTableCreateString(Binding.Binding binding) + { + StringBuilder str = new StringBuilder(); + str.Append(@"CREATE TABLE IF NOT EXISTS `{0}` ("); + foreach (var field in binding.Fields) + { + switch (field.Type) + { + case BindingType.UINT: + str.Append($@"`{field.Name}` int(10) unsigned NOT NULL DEFAULT '0', "); + break; + case BindingType.INT: + str.Append($@"`{field.Name}` int(11) NOT NULL DEFAULT '0', "); + break; + case BindingType.UINT8: + str.Append($@"`{field.Name}` tinyint unsigned NOT NULL DEFAULT '0', "); + break; + case BindingType.FLOAT: + str.Append($@"`{field.Name}` FLOAT NOT NULL DEFAULT '0', "); + break; + case BindingType.STRING_OFFSET: + str.Append($@"`{field.Name}` TEXT CHARACTER SET utf8, "); + break; + default: + throw new Exception($"ERROR: Unhandled type: {field.Type} on field: {field.Name} on binding: {binding.Name}"); + } + } + + var idField = binding.Fields.FirstOrDefault(record => record.Name.ToLower().Equals("id")); + if (idField != null && binding.OrderOutput) + str.Append($"PRIMARY KEY (`{idField.Name}`)) "); + else + { + str = str.Remove(str.Length - 2, 2); + str = str.Append(") "); + } + str.Append("ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 ROW_FORMAT=COMPRESSED KEY_BLOCK_SIZE=8;"); + return str.ToString(); + } + + public virtual void CreateAllTablesFromBindings() + { + throw new NotImplementedException(); + } + + public virtual void Dispose() + { + throw new NotImplementedException(); + } + + + public virtual void CommitChanges(string query, DataTable dataTable) + { + throw new NotImplementedException(); + } + + public virtual string EscapeString(string str) + { + throw new NotImplementedException(); + } + + public virtual void Execute(string p) + { + throw new NotImplementedException(); + } + + public virtual DataTable Query(string query) + { + throw new NotImplementedException(); + } + + public virtual object QuerySingleValue(string query) + { + throw new NotImplementedException(); + } + } +} diff --git a/SpellGUIV2/Sources/Database/AdapterFactory.cs b/SpellGUIV2/Sources/Database/AdapterFactory.cs index d83af28f..eda3b638 100644 --- a/SpellGUIV2/Sources/Database/AdapterFactory.cs +++ b/SpellGUIV2/Sources/Database/AdapterFactory.cs @@ -22,8 +22,10 @@ public IDatabaseAdapter GetAdapter(bool initialiseDatabase) return new MySQL(initialiseDatabase); case Config.Config.ConnectionType.SQLite: return new SQLite(); + case Config.Config.ConnectionType.MariaDB: + return new MariaDB(initialiseDatabase); default: - throw new Exception("Unknown config connection type, valid types: MySQL, SQLite"); + throw new Exception("Unknown config connection type, valid types: MySQL, MariaDB, SQLite"); } } diff --git a/SpellGUIV2/Sources/Database/MariaDB.cs b/SpellGUIV2/Sources/Database/MariaDB.cs new file mode 100644 index 00000000..5f96bc0e --- /dev/null +++ b/SpellGUIV2/Sources/Database/MariaDB.cs @@ -0,0 +1,179 @@ +using System; +using System.Data; +using System.Threading; +using NLog; +using MySqlConnector; + +namespace SpellEditor.Sources.Database +{ + public class MariaDB : AbstractAdapter + { + private static readonly Logger Logger = LogManager.GetCurrentClassLogger(); + + private readonly MySqlConnection _connection; + private Timer _heartbeat; + + public MariaDB(bool initialiseDatabase) + { + var builder = new MySqlConnectionStringBuilder + { + Server = Config.Config.Host, + UserID = Config.Config.User, + Password = Config.Config.Pass, + Port = uint.Parse(Config.Config.Port), + CharacterSet = "utf8mb4" + }; + + _connection = new MySqlConnection(builder.ConnectionString); + _connection.Open(); + + if (initialiseDatabase) + { + // Create DB if not exists and use + using (var cmd = _connection.CreateCommand()) + { + cmd.CommandText = string.Format("CREATE DATABASE IF NOT EXISTS `{0}`; USE `{0}`;", Config.Config.Database); + cmd.ExecuteNonQuery(); + } + } + else + { + // Use DB + using (var cmd = _connection.CreateCommand()) + { + cmd.CommandText = string.Format("USE `{0}`;", Config.Config.Database); + cmd.ExecuteNonQuery(); + } + } + + // Heartbeat keeps the connection alive, otherwise it can be killed by remote for inactivity + // Object reference needs to be held to prevent garbage collection. + _heartbeat = CreateKeepAliveTimer(TimeSpan.FromMinutes(2)); + } + + public override void Dispose() + { + _heartbeat?.Dispose(); + _heartbeat = null; + if (_connection != null && _connection.State != ConnectionState.Closed) + { + try + { + _connection.Close(); + } + catch (Exception exception) + { + Logger.Error(exception); + } + finally + { + _connection.Dispose(); + } + } + } + + public override void CreateAllTablesFromBindings() + { + lock (_syncLock) + { + foreach (var createStatement in GetAllTableCreateStrings()) + { + using (var cmd = _connection.CreateCommand()) + { + cmd.CommandText = createStatement; + Logger.Trace(cmd.CommandText); + cmd.ExecuteNonQuery(); + } + } + } + } + + public override DataTable Query(string query) + { + Logger.Trace(query); + lock (_syncLock) + { + using (var adapter = new MySqlDataAdapter(query, _connection)) + { + using (var dataSet = new DataSet()) + { + adapter.SelectCommand.CommandTimeout = 0; + adapter.Fill(dataSet); + return dataSet.Tables[0]; + } + } + } + } + + public override object QuerySingleValue(string query) + { + Logger.Trace(query); + lock (_syncLock) + { + using (var adapter = new MySqlDataAdapter(query, _connection)) + { + using (var dataSet = new DataSet()) + { + adapter.SelectCommand.CommandTimeout = 0; + adapter.Fill(dataSet); + var table = dataSet.Tables[0]; + return table.Rows.Count > 0 ? table.Rows[0][0] : null; + } + } + } + } + + public override void CommitChanges(string query, DataTable dataTable) + { + if (Updating) + return; + + Logger.Trace(query); + lock (_syncLock) + { + using (var adapter = new MySqlDataAdapter()) + { + using (var mcb = new MySqlCommandBuilder(adapter)) + { + mcb.ConflictOption = ConflictOption.OverwriteChanges; + adapter.SelectCommand = new MySqlCommand(query, _connection); + adapter.Update(dataTable); + dataTable.AcceptChanges(); + } + } + } + } + + public override void Execute(string p) + { + if (Updating) + return; + + Logger.Trace(p); + lock (_syncLock) + { + using (var cmd = _connection.CreateCommand()) + { + cmd.CommandText = p; + cmd.ExecuteNonQuery(); + } + } + } + + public override string EscapeString(string keyWord) + { + keyWord = keyWord.Replace("'", "''"); + keyWord = keyWord.Replace("\\", "\\\\"); + return keyWord; + } + + private Timer CreateKeepAliveTimer(TimeSpan interval) + { + return new Timer( + (e) => Execute("SELECT 1"), + null, + interval, + interval); + } + } +} diff --git a/SpellGUIV2/Sources/Database/MySQL.cs b/SpellGUIV2/Sources/Database/MySQL.cs index 9f60faf5..c7cca99e 100644 --- a/SpellGUIV2/Sources/Database/MySQL.cs +++ b/SpellGUIV2/Sources/Database/MySQL.cs @@ -1,22 +1,17 @@ using MySql.Data.MySqlClient; -using SpellEditor.Sources.Binding; using System; using System.Data; -using System.Linq; -using System.Text; using System.Threading; using NLog; namespace SpellEditor.Sources.Database { - public class MySQL : IDatabaseAdapter, IDisposable + public class MySQL : AbstractAdapter { private static readonly Logger Logger = LogManager.GetCurrentClassLogger(); - private readonly object _syncLock = new object(); private readonly MySqlConnection _connection; private Timer _heartbeat; - public bool Updating { get; set; } public MySQL(bool initialiseDatabase) { @@ -49,7 +44,7 @@ public MySQL(bool initialiseDatabase) _heartbeat = CreateKeepAliveTimer(TimeSpan.FromMinutes(2)); } - public void Dispose() + public override void Dispose() { _heartbeat?.Dispose(); _heartbeat = null; @@ -70,15 +65,15 @@ public void Dispose() } } - public void CreateAllTablesFromBindings() + public override void CreateAllTablesFromBindings() { lock (_syncLock) { - foreach (var binding in BindingManager.GetInstance().GetAllBindings()) + foreach (var createStatement in GetAllTableCreateStrings()) { using (var cmd = _connection.CreateCommand()) { - cmd.CommandText = string.Format(GetTableCreateString(binding), binding.Name.ToLower()); + cmd.CommandText = createStatement; Logger.Trace(cmd.CommandText); cmd.ExecuteNonQuery(); } @@ -86,7 +81,7 @@ public void CreateAllTablesFromBindings() } } - public DataTable Query(string query) + public override DataTable Query(string query) { Logger.Trace(query); lock (_syncLock) @@ -103,7 +98,7 @@ public DataTable Query(string query) } } - public object QuerySingleValue(string query) + public override object QuerySingleValue(string query) { Logger.Trace(query); lock (_syncLock) @@ -121,7 +116,7 @@ public object QuerySingleValue(string query) } } - public void CommitChanges(string query, DataTable dataTable) + public override void CommitChanges(string query, DataTable dataTable) { if (Updating) return; @@ -142,7 +137,7 @@ public void CommitChanges(string query, DataTable dataTable) } } - public void Execute(string p) + public override void Execute(string p) { if (Updating) return; @@ -158,48 +153,7 @@ public void Execute(string p) } } - public string GetTableCreateString(Binding.Binding binding) - { - StringBuilder str = new StringBuilder(); - str.Append(@"CREATE TABLE IF NOT EXISTS `{0}` ("); - foreach (var field in binding.Fields) - { - switch (field.Type) - { - case BindingType.UINT: - str.Append($@"`{field.Name}` int(10) unsigned NOT NULL DEFAULT '0', "); - break; - case BindingType.INT: - str.Append($@"`{field.Name}` int(11) NOT NULL DEFAULT '0', "); - break; - case BindingType.UINT8: - str.Append($@"`{field.Name}` tinyint unsigned NOT NULL DEFAULT '0', "); - break; - case BindingType.FLOAT: - str.Append($@"`{field.Name}` FLOAT NOT NULL DEFAULT '0', "); - break; - case BindingType.STRING_OFFSET: - str.Append($@"`{field.Name}` TEXT CHARACTER SET utf8, "); - break; - default: - throw new Exception($"ERROR: Unhandled type: {field.Type} on field: {field.Name} on binding: {binding.Name}"); - - } - } - - var idField = binding.Fields.FirstOrDefault(record => record.Name.ToLower().Equals("id")); - if (idField != null && binding.OrderOutput) - str.Append($"PRIMARY KEY (`{idField.Name}`)) "); - else - { - str = str.Remove(str.Length - 2, 2); - str = str.Append(") "); - } - str.Append("ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 ROW_FORMAT=COMPRESSED KEY_BLOCK_SIZE=8;"); - return str.ToString(); - } - - public string EscapeString(string keyWord) + public override string EscapeString(string keyWord) { keyWord = keyWord.Replace("'", "''"); keyWord = keyWord.Replace("\\", "\\\\"); diff --git a/SpellGUIV2/Sources/Database/SQLite.cs b/SpellGUIV2/Sources/Database/SQLite.cs index 4341b456..6bb5dace 100644 --- a/SpellGUIV2/Sources/Database/SQLite.cs +++ b/SpellGUIV2/Sources/Database/SQLite.cs @@ -1,21 +1,15 @@ using System; using System.Data; using System.Data.SQLite; -using System.Text; -using SpellEditor.Sources.Binding; -using System.Linq; using NLog; namespace SpellEditor.Sources.Database { - public class SQLite : IDatabaseAdapter + public class SQLite : AbstractAdapter { private static readonly Logger Logger = LogManager.GetCurrentClassLogger(); - private readonly object _syncLock = new object(); - private readonly SQLiteConnection _connection; - - public bool Updating { get; set; } + private SQLiteConnection _connection; public SQLite() { @@ -25,7 +19,7 @@ public SQLite() _connection.Open(); } - public void Dispose() + public override void Dispose() { try { @@ -37,17 +31,16 @@ public void Dispose() } } - // Explitly not handling disposing the connection like MySQL does. SQLite is automatically cleaned up. - - public void CreateAllTablesFromBindings() + public override void CreateAllTablesFromBindings() { - foreach (var binding in BindingManager.GetInstance().GetAllBindings()) + + lock (_syncLock) { - lock (_syncLock) + foreach (var createStatement in GetAllTableCreateStrings()) { using (var cmd = _connection.CreateCommand()) { - cmd.CommandText = string.Format(GetTableCreateString(binding), binding.Name.ToLower()); + cmd.CommandText = createStatement; Logger.Trace(cmd.CommandText); cmd.ExecuteNonQuery(); } @@ -55,7 +48,7 @@ public void CreateAllTablesFromBindings() } } - public DataTable Query(string query) + public override DataTable Query(string query) { Logger.Trace(query); lock (_syncLock) @@ -73,7 +66,7 @@ public DataTable Query(string query) } } - public object QuerySingleValue(string query) + public override object QuerySingleValue(string query) { Logger.Trace(query); lock (_syncLock) @@ -91,7 +84,7 @@ public object QuerySingleValue(string query) } } - public void CommitChanges(string query, DataTable dataTable) + public override void CommitChanges(string query, DataTable dataTable) { if (Updating) return; @@ -112,7 +105,7 @@ public void CommitChanges(string query, DataTable dataTable) } } - public void Execute(string p) + public override void Execute(string p) { if (Updating) return; @@ -127,7 +120,7 @@ public void Execute(string p) } } } - + /* public string GetTableCreateString(Binding.Binding binding) { StringBuilder str = new StringBuilder(); @@ -164,8 +157,9 @@ public string GetTableCreateString(Binding.Binding binding) str.Append(");"); return str.ToString(); } + */ - public string EscapeString(string keyWord) + public override string EscapeString(string keyWord) { keyWord = keyWord.Replace("'", "''"); return keyWord; diff --git a/SpellGUIV2/SpellEditor.csproj b/SpellGUIV2/SpellEditor.csproj index 6ae73ceb..b036532f 100644 --- a/SpellGUIV2/SpellEditor.csproj +++ b/SpellGUIV2/SpellEditor.csproj @@ -10,7 +10,7 @@ Properties SpellEditor SpellEditor - v4.5.2 + v4.8 512 {60dc8134-eba5-43b8-bcc9-bb4bc16c2548};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} 4 @@ -64,6 +64,9 @@ false + + ..\packages\BouncyCastle.Cryptography.2.4.0\lib\net461\BouncyCastle.Cryptography.dll + ..\packages\ControlzEx.3.0.2.4\lib\net45\ControlzEx.dll @@ -77,23 +80,32 @@ ..\packages\EntityFramework.6.4.4\lib\net45\EntityFramework.SqlServer.dll - - ..\packages\Google.Protobuf.3.19.4\lib\net45\Google.Protobuf.dll + + ..\packages\Google.Protobuf.3.26.1\lib\net45\Google.Protobuf.dll - - ..\packages\K4os.Compression.LZ4.1.2.6\lib\net45\K4os.Compression.LZ4.dll + + ..\packages\K4os.Compression.LZ4.1.3.8\lib\net462\K4os.Compression.LZ4.dll - - ..\packages\K4os.Compression.LZ4.Streams.1.2.6\lib\net45\K4os.Compression.LZ4.Streams.dll + + ..\packages\K4os.Compression.LZ4.Streams.1.3.8\lib\net462\K4os.Compression.LZ4.Streams.dll - - ..\packages\K4os.Hash.xxHash.1.0.6\lib\net45\K4os.Hash.xxHash.dll + + ..\packages\K4os.Hash.xxHash.1.0.8\lib\net462\K4os.Hash.xxHash.dll ..\packages\MahApps.Metro.1.3.0\lib\net45\MahApps.Metro.dll - - ..\packages\MySql.Data.8.0.29\lib\net452\MySql.Data.dll + + ..\packages\Microsoft.Bcl.AsyncInterfaces.5.0.0\lib\net461\Microsoft.Bcl.AsyncInterfaces.dll + + + ..\packages\Microsoft.Extensions.Logging.Abstractions.7.0.1\lib\net462\Microsoft.Extensions.Logging.Abstractions.dll + + + ..\packages\MySql.Data.9.0.0\lib\net48\MySql.Data.dll + + + ..\packages\MySqlConnector.2.3.7\lib\net48\MySqlConnector.dll ..\packages\NLog.4.7.0\lib\net45\NLog.dll @@ -108,32 +120,44 @@ + + ..\packages\System.Configuration.ConfigurationManager.8.0.0\lib\net462\System.Configuration.ConfigurationManager.dll + - - ..\packages\System.Data.SQLite.Core.1.0.104.0\lib\net451\System.Data.SQLite.dll - True - False + + ..\packages\Stub.System.Data.SQLite.Core.NetFramework.1.0.118.0\lib\net46\System.Data.SQLite.dll - - ..\packages\System.Data.SQLite.EF6.1.0.104.0\lib\net451\System.Data.SQLite.EF6.dll - True + + ..\packages\System.Data.SQLite.EF6.1.0.118.0\lib\net46\System.Data.SQLite.EF6.dll - - ..\packages\System.Data.SQLite.Linq.1.0.104.0\lib\net451\System.Data.SQLite.Linq.dll - True + + ..\packages\System.Data.SQLite.Linq.1.0.118.0\lib\net46\System.Data.SQLite.Linq.dll + + + ..\packages\System.Diagnostics.DiagnosticSource.8.0.1\lib\net462\System.Diagnostics.DiagnosticSource.dll + + ..\packages\System.IO.Pipelines.5.0.2\lib\net461\System.IO.Pipelines.dll + - - ..\packages\System.Memory.4.5.4\lib\netstandard1.1\System.Memory.dll + + ..\packages\System.Memory.4.5.5\lib\net461\System.Memory.dll + + + + ..\packages\System.Numerics.Vectors.4.5.0\lib\net46\System.Numerics.Vectors.dll - - ..\packages\System.Runtime.CompilerServices.Unsafe.5.0.0\lib\net45\System.Runtime.CompilerServices.Unsafe.dll + + ..\packages\System.Runtime.CompilerServices.Unsafe.6.0.0\lib\net461\System.Runtime.CompilerServices.Unsafe.dll + + ..\packages\System.Threading.Tasks.Extensions.4.5.4\lib\net461\System.Threading.Tasks.Extensions.dll + @@ -147,14 +171,11 @@ 4.0 - - ..\packages\MySql.Data.8.0.29\lib\net452\Ubiety.Dns.Core.dll - - - ..\packages\MySql.Data.8.0.29\lib\net452\ZstdNet.dll + + ..\packages\ZstdSharp.Port.0.8.0\lib\net462\ZstdSharp.dll @@ -186,6 +207,8 @@ + + @@ -323,20 +346,20 @@ - 这台计算机上缺少此项目引用的 NuGet 程序包。使用“NuGet 程序包还原”可下载这些程序包。有关更多信息,请参见 http://go.microsoft.com/fwlink/?LinkID=322105。缺少的文件是 {0}。 - + +