diff --git a/Emby.Server.Implementations/ApplicationHost.cs b/Emby.Server.Implementations/ApplicationHost.cs index f36d465dd1..294e4f5806 100644 --- a/Emby.Server.Implementations/ApplicationHost.cs +++ b/Emby.Server.Implementations/ApplicationHost.cs @@ -773,12 +773,11 @@ namespace Emby.Server.Implementations _displayPreferencesRepository = new SqliteDisplayPreferencesRepository( LoggerFactory.CreateLogger(), - JsonSerializer, ApplicationPaths, FileSystemManager); serviceCollection.AddSingleton(_displayPreferencesRepository); - ItemRepository = new SqliteItemRepository(ServerConfigurationManager, this, JsonSerializer, LoggerFactory, LocalizationManager); + ItemRepository = new SqliteItemRepository(ServerConfigurationManager, this, LoggerFactory.CreateLogger(), LocalizationManager); serviceCollection.AddSingleton(ItemRepository); AuthenticationRepository = GetAuthenticationRepository(); @@ -979,8 +978,7 @@ namespace Emby.Server.Implementations { var repo = new SqliteUserRepository( LoggerFactory.CreateLogger(), - ApplicationPaths, - JsonSerializer); + ApplicationPaths); repo.Initialize(); diff --git a/Emby.Server.Implementations/Data/SqliteDisplayPreferencesRepository.cs b/Emby.Server.Implementations/Data/SqliteDisplayPreferencesRepository.cs index 1a67ab912a..2cd4d65b3a 100644 --- a/Emby.Server.Implementations/Data/SqliteDisplayPreferencesRepository.cs +++ b/Emby.Server.Implementations/Data/SqliteDisplayPreferencesRepository.cs @@ -2,44 +2,44 @@ using System; using System.Collections.Generic; using System.Globalization; using System.IO; +using System.Text.Json; using System.Threading; using MediaBrowser.Common.Configuration; using MediaBrowser.Common.Extensions; +using MediaBrowser.Common.Json; using MediaBrowser.Controller.Persistence; using MediaBrowser.Model.Entities; using MediaBrowser.Model.IO; -using MediaBrowser.Model.Serialization; using Microsoft.Extensions.Logging; using SQLitePCL.pretty; namespace Emby.Server.Implementations.Data { /// - /// Class SQLiteDisplayPreferencesRepository + /// Class SQLiteDisplayPreferencesRepository. /// public class SqliteDisplayPreferencesRepository : BaseSqliteRepository, IDisplayPreferencesRepository { private readonly IFileSystem _fileSystem; - public SqliteDisplayPreferencesRepository(ILogger logger, IJsonSerializer jsonSerializer, IApplicationPaths appPaths, IFileSystem fileSystem) + private readonly JsonSerializerOptions _jsonOptions; + + public SqliteDisplayPreferencesRepository(ILogger logger, IApplicationPaths appPaths, IFileSystem fileSystem) : base(logger) { - _jsonSerializer = jsonSerializer; _fileSystem = fileSystem; + + _jsonOptions = JsonDefaults.GetOptions(); + DbFilePath = Path.Combine(appPaths.DataPath, "displaypreferences.db"); } /// - /// Gets the name of the repository + /// Gets the name of the repository. /// /// The name. public string Name => "SQLite"; - /// - /// The _json serializer - /// - private readonly IJsonSerializer _jsonSerializer; - public void Initialize() { try @@ -106,7 +106,7 @@ namespace Emby.Server.Implementations.Data private void SaveDisplayPreferences(DisplayPreferences displayPreferences, Guid userId, string client, IDatabaseConnection connection) { - var serialized = _jsonSerializer.SerializeToBytes(displayPreferences); + var serialized = JsonSerializer.SerializeToUtf8Bytes(displayPreferences, _jsonOptions); using (var statement = connection.PrepareStatement("replace into userdisplaypreferences (id, userid, client, data) values (@id, @userId, @client, @data)")) { @@ -198,15 +198,13 @@ namespace Emby.Server.Implementations.Data var list = new List(); using (var connection = GetConnection(true)) + using (var statement = connection.PrepareStatement("select data from userdisplaypreferences where userId=@userId")) { - using (var statement = connection.PrepareStatement("select data from userdisplaypreferences where userId=@userId")) - { - statement.TryBind("@userId", userId.ToGuidBlob()); + statement.TryBind("@userId", userId.ToGuidBlob()); - foreach (var row in statement.ExecuteQuery()) - { - list.Add(Get(row)); - } + foreach (var row in statement.ExecuteQuery()) + { + list.Add(Get(row)); } } @@ -214,7 +212,7 @@ namespace Emby.Server.Implementations.Data } private DisplayPreferences Get(IReadOnlyList row) - => _jsonSerializer.DeserializeFromString(row.GetString(0)); + => JsonSerializer.Deserialize(row[0].ToBlob(), _jsonOptions); public void SaveDisplayPreferences(DisplayPreferences displayPreferences, string userId, string client, CancellationToken cancellationToken) => SaveDisplayPreferences(displayPreferences, new Guid(userId), client, cancellationToken); diff --git a/Emby.Server.Implementations/Data/SqliteItemRepository.cs b/Emby.Server.Implementations/Data/SqliteItemRepository.cs index 96f90b831d..31a661c5d9 100644 --- a/Emby.Server.Implementations/Data/SqliteItemRepository.cs +++ b/Emby.Server.Implementations/Data/SqliteItemRepository.cs @@ -5,8 +5,11 @@ using System.IO; using System.Linq; using System.Runtime.Serialization; using System.Text; +using System.Text.Json; +using System.Text.Json.Serialization; using System.Threading; using Emby.Server.Implementations.Playlists; +using MediaBrowser.Common.Json; using MediaBrowser.Controller; using MediaBrowser.Controller.Channels; using MediaBrowser.Controller.Configuration; @@ -38,14 +41,6 @@ namespace Emby.Server.Implementations.Data { private const string ChaptersTableName = "Chapters2"; - private readonly TypeMapper _typeMapper; - - /// - /// Gets the json serializer. - /// - /// The json serializer. - private readonly IJsonSerializer _jsonSerializer; - /// /// The _app paths /// @@ -53,33 +48,31 @@ namespace Emby.Server.Implementations.Data private readonly IServerApplicationHost _appHost; private readonly ILocalizationManager _localization; + private readonly TypeMapper _typeMapper; + private readonly JsonSerializerOptions _jsonOptions; + /// /// Initializes a new instance of the class. /// public SqliteItemRepository( IServerConfigurationManager config, IServerApplicationHost appHost, - IJsonSerializer jsonSerializer, - ILoggerFactory loggerFactory, + ILogger logger, ILocalizationManager localization) - : base(loggerFactory.CreateLogger(nameof(SqliteItemRepository))) + : base(logger) { if (config == null) { throw new ArgumentNullException(nameof(config)); } - if (jsonSerializer == null) - { - throw new ArgumentNullException(nameof(jsonSerializer)); - } - - _appHost = appHost; _config = config; - _jsonSerializer = jsonSerializer; - _typeMapper = new TypeMapper(); + _appHost = appHost; _localization = localization; + _typeMapper = new TypeMapper(); + _jsonOptions = JsonDefaults.GetOptions(); + DbFilePath = Path.Combine(_config.ApplicationPaths.DataPath, "library.db"); } @@ -671,7 +664,7 @@ namespace Emby.Server.Implementations.Data if (TypeRequiresDeserialization(item.GetType())) { - saveItemStatement.TryBind("@data", _jsonSerializer.SerializeToBytes(item)); + saveItemStatement.TryBind("@data", JsonSerializer.SerializeToUtf8Bytes(item, _jsonOptions)); } else { @@ -1302,11 +1295,11 @@ namespace Emby.Server.Implementations.Data { try { - item = _jsonSerializer.DeserializeFromString(reader.GetString(1), type) as BaseItem; + item = JsonSerializer.Deserialize(reader[1].ToBlob(), type, _jsonOptions) as BaseItem; } - catch (SerializationException ex) + catch (JsonException ex) { - Logger.LogError(ex, "Error deserializing item"); + Logger.LogError(ex, "Error deserializing item with JSON: {Data}", reader.GetString(1)); } } diff --git a/Emby.Server.Implementations/Data/SqliteUserRepository.cs b/Emby.Server.Implementations/Data/SqliteUserRepository.cs index 11629b3895..80fe278f82 100644 --- a/Emby.Server.Implementations/Data/SqliteUserRepository.cs +++ b/Emby.Server.Implementations/Data/SqliteUserRepository.cs @@ -1,10 +1,11 @@ using System; using System.Collections.Generic; using System.IO; +using System.Text.Json; +using MediaBrowser.Common.Json; using MediaBrowser.Controller; using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Persistence; -using MediaBrowser.Model.Serialization; using Microsoft.Extensions.Logging; using SQLitePCL.pretty; @@ -15,15 +16,14 @@ namespace Emby.Server.Implementations.Data /// public class SqliteUserRepository : BaseSqliteRepository, IUserRepository { - private readonly IJsonSerializer _jsonSerializer; + private readonly JsonSerializerOptions _jsonOptions; public SqliteUserRepository( ILogger logger, - IServerApplicationPaths appPaths, - IJsonSerializer jsonSerializer) + IServerApplicationPaths appPaths) : base(logger) { - _jsonSerializer = jsonSerializer; + _jsonOptions = JsonDefaults.GetOptions();; DbFilePath = Path.Combine(appPaths.DataPath, "users.db"); } @@ -84,7 +84,7 @@ namespace Emby.Server.Implementations.Data } user.Password = null; - var serialized = _jsonSerializer.SerializeToBytes(user); + var serialized = JsonSerializer.SerializeToUtf8Bytes(user, _jsonOptions); connection.RunInTransaction(db => { @@ -108,7 +108,7 @@ namespace Emby.Server.Implementations.Data throw new ArgumentNullException(nameof(user)); } - var serialized = _jsonSerializer.SerializeToBytes(user); + var serialized = JsonSerializer.SerializeToUtf8Bytes(user, _jsonOptions); using (var connection = GetConnection()) { @@ -142,7 +142,7 @@ namespace Emby.Server.Implementations.Data throw new ArgumentNullException(nameof(user)); } - var serialized = _jsonSerializer.SerializeToBytes(user); + var serialized = JsonSerializer.SerializeToUtf8Bytes(user, _jsonOptions); using (var connection = GetConnection()) { @@ -179,7 +179,7 @@ namespace Emby.Server.Implementations.Data var id = row[0].ToInt64(); var guid = row[1].ReadGuidFromBlob(); - var user = _jsonSerializer.DeserializeFromString(row.GetString(2)); + var user = JsonSerializer.Deserialize(row[2].ToBlob(), _jsonOptions); user.InternalId = id; user.Id = guid; return user; diff --git a/MediaBrowser.Common/Json/Converters/GuidConverter.cs b/MediaBrowser.Common/Json/Converters/GuidConverter.cs new file mode 100644 index 0000000000..3081e12eee --- /dev/null +++ b/MediaBrowser.Common/Json/Converters/GuidConverter.cs @@ -0,0 +1,20 @@ +using System; +using System.Text.Json; +using System.Text.Json.Serialization; + +namespace MediaBrowser.Common.Json.Converters +{ + /// + /// Converts a GUID object or value to/from JSON. + /// + public class GuidConverter : JsonConverter + { + /// + public override Guid Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + => new Guid(reader.GetString()); + + /// + public override void Write(Utf8JsonWriter writer, Guid value, JsonSerializerOptions options) + => writer.WriteStringValue(value); + } +} diff --git a/MediaBrowser.Common/Json/JsonDefaults.cs b/MediaBrowser.Common/Json/JsonDefaults.cs new file mode 100644 index 0000000000..4ba0d5a1a5 --- /dev/null +++ b/MediaBrowser.Common/Json/JsonDefaults.cs @@ -0,0 +1,30 @@ +using System.Text.Json; +using System.Text.Json.Serialization; +using MediaBrowser.Common.Json.Converters; + +namespace MediaBrowser.Common.Json +{ + /// + /// Helper class for having compatible JSON throughout the codebase. + /// + public static class JsonDefaults + { + /// + /// Gets the default options. + /// + /// The default options. + public static JsonSerializerOptions GetOptions() + { + var options = new JsonSerializerOptions() + { + ReadCommentHandling = JsonCommentHandling.Disallow, + WriteIndented = false + }; + + options.Converters.Add(new GuidConverter()); + options.Converters.Add(new JsonStringEnumConverter()); + + return options; + } + } +} diff --git a/MediaBrowser.Common/MediaBrowser.Common.csproj b/MediaBrowser.Common/MediaBrowser.Common.csproj index 1a40f5ea2f..dc1c967cdf 100644 --- a/MediaBrowser.Common/MediaBrowser.Common.csproj +++ b/MediaBrowser.Common/MediaBrowser.Common.csproj @@ -14,6 +14,7 @@ +