Merge pull request #1854 from Bond-009/json

Use System.Text.Json api for databases
This commit is contained in:
Vasily 2019-10-10 18:15:48 +03:00 committed by GitHub
commit 79f9887625
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 95 additions and 55 deletions

View File

@ -773,12 +773,11 @@ namespace Emby.Server.Implementations
_displayPreferencesRepository = new SqliteDisplayPreferencesRepository( _displayPreferencesRepository = new SqliteDisplayPreferencesRepository(
LoggerFactory.CreateLogger<SqliteDisplayPreferencesRepository>(), LoggerFactory.CreateLogger<SqliteDisplayPreferencesRepository>(),
JsonSerializer,
ApplicationPaths, ApplicationPaths,
FileSystemManager); FileSystemManager);
serviceCollection.AddSingleton<IDisplayPreferencesRepository>(_displayPreferencesRepository); serviceCollection.AddSingleton<IDisplayPreferencesRepository>(_displayPreferencesRepository);
ItemRepository = new SqliteItemRepository(ServerConfigurationManager, this, JsonSerializer, LoggerFactory, LocalizationManager); ItemRepository = new SqliteItemRepository(ServerConfigurationManager, this, LoggerFactory.CreateLogger<SqliteItemRepository>(), LocalizationManager);
serviceCollection.AddSingleton<IItemRepository>(ItemRepository); serviceCollection.AddSingleton<IItemRepository>(ItemRepository);
AuthenticationRepository = GetAuthenticationRepository(); AuthenticationRepository = GetAuthenticationRepository();
@ -979,8 +978,7 @@ namespace Emby.Server.Implementations
{ {
var repo = new SqliteUserRepository( var repo = new SqliteUserRepository(
LoggerFactory.CreateLogger<SqliteUserRepository>(), LoggerFactory.CreateLogger<SqliteUserRepository>(),
ApplicationPaths, ApplicationPaths);
JsonSerializer);
repo.Initialize(); repo.Initialize();

View File

@ -2,44 +2,44 @@ using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Globalization; using System.Globalization;
using System.IO; using System.IO;
using System.Text.Json;
using System.Threading; using System.Threading;
using MediaBrowser.Common.Configuration; using MediaBrowser.Common.Configuration;
using MediaBrowser.Common.Extensions; using MediaBrowser.Common.Extensions;
using MediaBrowser.Common.Json;
using MediaBrowser.Controller.Persistence; using MediaBrowser.Controller.Persistence;
using MediaBrowser.Model.Entities; using MediaBrowser.Model.Entities;
using MediaBrowser.Model.IO; using MediaBrowser.Model.IO;
using MediaBrowser.Model.Serialization;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
using SQLitePCL.pretty; using SQLitePCL.pretty;
namespace Emby.Server.Implementations.Data namespace Emby.Server.Implementations.Data
{ {
/// <summary> /// <summary>
/// Class SQLiteDisplayPreferencesRepository /// Class SQLiteDisplayPreferencesRepository.
/// </summary> /// </summary>
public class SqliteDisplayPreferencesRepository : BaseSqliteRepository, IDisplayPreferencesRepository public class SqliteDisplayPreferencesRepository : BaseSqliteRepository, IDisplayPreferencesRepository
{ {
private readonly IFileSystem _fileSystem; private readonly IFileSystem _fileSystem;
public SqliteDisplayPreferencesRepository(ILogger<SqliteDisplayPreferencesRepository> logger, IJsonSerializer jsonSerializer, IApplicationPaths appPaths, IFileSystem fileSystem) private readonly JsonSerializerOptions _jsonOptions;
public SqliteDisplayPreferencesRepository(ILogger<SqliteDisplayPreferencesRepository> logger, IApplicationPaths appPaths, IFileSystem fileSystem)
: base(logger) : base(logger)
{ {
_jsonSerializer = jsonSerializer;
_fileSystem = fileSystem; _fileSystem = fileSystem;
_jsonOptions = JsonDefaults.GetOptions();
DbFilePath = Path.Combine(appPaths.DataPath, "displaypreferences.db"); DbFilePath = Path.Combine(appPaths.DataPath, "displaypreferences.db");
} }
/// <summary> /// <summary>
/// Gets the name of the repository /// Gets the name of the repository.
/// </summary> /// </summary>
/// <value>The name.</value> /// <value>The name.</value>
public string Name => "SQLite"; public string Name => "SQLite";
/// <summary>
/// The _json serializer
/// </summary>
private readonly IJsonSerializer _jsonSerializer;
public void Initialize() public void Initialize()
{ {
try try
@ -106,7 +106,7 @@ namespace Emby.Server.Implementations.Data
private void SaveDisplayPreferences(DisplayPreferences displayPreferences, Guid userId, string client, IDatabaseConnection connection) 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)")) 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<DisplayPreferences>(); var list = new List<DisplayPreferences>();
using (var connection = GetConnection(true)) 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()) foreach (var row in statement.ExecuteQuery())
{ {
list.Add(Get(row)); list.Add(Get(row));
}
} }
} }
@ -214,7 +212,7 @@ namespace Emby.Server.Implementations.Data
} }
private DisplayPreferences Get(IReadOnlyList<IResultSetValue> row) private DisplayPreferences Get(IReadOnlyList<IResultSetValue> row)
=> _jsonSerializer.DeserializeFromString<DisplayPreferences>(row.GetString(0)); => JsonSerializer.Deserialize<DisplayPreferences>(row[0].ToBlob(), _jsonOptions);
public void SaveDisplayPreferences(DisplayPreferences displayPreferences, string userId, string client, CancellationToken cancellationToken) public void SaveDisplayPreferences(DisplayPreferences displayPreferences, string userId, string client, CancellationToken cancellationToken)
=> SaveDisplayPreferences(displayPreferences, new Guid(userId), client, cancellationToken); => SaveDisplayPreferences(displayPreferences, new Guid(userId), client, cancellationToken);

View File

@ -5,8 +5,11 @@ using System.IO;
using System.Linq; using System.Linq;
using System.Runtime.Serialization; using System.Runtime.Serialization;
using System.Text; using System.Text;
using System.Text.Json;
using System.Text.Json.Serialization;
using System.Threading; using System.Threading;
using Emby.Server.Implementations.Playlists; using Emby.Server.Implementations.Playlists;
using MediaBrowser.Common.Json;
using MediaBrowser.Controller; using MediaBrowser.Controller;
using MediaBrowser.Controller.Channels; using MediaBrowser.Controller.Channels;
using MediaBrowser.Controller.Configuration; using MediaBrowser.Controller.Configuration;
@ -38,14 +41,6 @@ namespace Emby.Server.Implementations.Data
{ {
private const string ChaptersTableName = "Chapters2"; private const string ChaptersTableName = "Chapters2";
private readonly TypeMapper _typeMapper;
/// <summary>
/// Gets the json serializer.
/// </summary>
/// <value>The json serializer.</value>
private readonly IJsonSerializer _jsonSerializer;
/// <summary> /// <summary>
/// The _app paths /// The _app paths
/// </summary> /// </summary>
@ -53,33 +48,31 @@ namespace Emby.Server.Implementations.Data
private readonly IServerApplicationHost _appHost; private readonly IServerApplicationHost _appHost;
private readonly ILocalizationManager _localization; private readonly ILocalizationManager _localization;
private readonly TypeMapper _typeMapper;
private readonly JsonSerializerOptions _jsonOptions;
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="SqliteItemRepository"/> class. /// Initializes a new instance of the <see cref="SqliteItemRepository"/> class.
/// </summary> /// </summary>
public SqliteItemRepository( public SqliteItemRepository(
IServerConfigurationManager config, IServerConfigurationManager config,
IServerApplicationHost appHost, IServerApplicationHost appHost,
IJsonSerializer jsonSerializer, ILogger<SqliteItemRepository> logger,
ILoggerFactory loggerFactory,
ILocalizationManager localization) ILocalizationManager localization)
: base(loggerFactory.CreateLogger(nameof(SqliteItemRepository))) : base(logger)
{ {
if (config == null) if (config == null)
{ {
throw new ArgumentNullException(nameof(config)); throw new ArgumentNullException(nameof(config));
} }
if (jsonSerializer == null)
{
throw new ArgumentNullException(nameof(jsonSerializer));
}
_appHost = appHost;
_config = config; _config = config;
_jsonSerializer = jsonSerializer; _appHost = appHost;
_typeMapper = new TypeMapper();
_localization = localization; _localization = localization;
_typeMapper = new TypeMapper();
_jsonOptions = JsonDefaults.GetOptions();
DbFilePath = Path.Combine(_config.ApplicationPaths.DataPath, "library.db"); DbFilePath = Path.Combine(_config.ApplicationPaths.DataPath, "library.db");
} }
@ -671,7 +664,7 @@ namespace Emby.Server.Implementations.Data
if (TypeRequiresDeserialization(item.GetType())) if (TypeRequiresDeserialization(item.GetType()))
{ {
saveItemStatement.TryBind("@data", _jsonSerializer.SerializeToBytes(item)); saveItemStatement.TryBind("@data", JsonSerializer.SerializeToUtf8Bytes(item, _jsonOptions));
} }
else else
{ {
@ -1302,11 +1295,11 @@ namespace Emby.Server.Implementations.Data
{ {
try 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));
} }
} }

View File

@ -1,10 +1,11 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.IO; using System.IO;
using System.Text.Json;
using MediaBrowser.Common.Json;
using MediaBrowser.Controller; using MediaBrowser.Controller;
using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Persistence; using MediaBrowser.Controller.Persistence;
using MediaBrowser.Model.Serialization;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
using SQLitePCL.pretty; using SQLitePCL.pretty;
@ -15,15 +16,14 @@ namespace Emby.Server.Implementations.Data
/// </summary> /// </summary>
public class SqliteUserRepository : BaseSqliteRepository, IUserRepository public class SqliteUserRepository : BaseSqliteRepository, IUserRepository
{ {
private readonly IJsonSerializer _jsonSerializer; private readonly JsonSerializerOptions _jsonOptions;
public SqliteUserRepository( public SqliteUserRepository(
ILogger<SqliteUserRepository> logger, ILogger<SqliteUserRepository> logger,
IServerApplicationPaths appPaths, IServerApplicationPaths appPaths)
IJsonSerializer jsonSerializer)
: base(logger) : base(logger)
{ {
_jsonSerializer = jsonSerializer; _jsonOptions = JsonDefaults.GetOptions();;
DbFilePath = Path.Combine(appPaths.DataPath, "users.db"); DbFilePath = Path.Combine(appPaths.DataPath, "users.db");
} }
@ -84,7 +84,7 @@ namespace Emby.Server.Implementations.Data
} }
user.Password = null; user.Password = null;
var serialized = _jsonSerializer.SerializeToBytes(user); var serialized = JsonSerializer.SerializeToUtf8Bytes(user, _jsonOptions);
connection.RunInTransaction(db => connection.RunInTransaction(db =>
{ {
@ -108,7 +108,7 @@ namespace Emby.Server.Implementations.Data
throw new ArgumentNullException(nameof(user)); throw new ArgumentNullException(nameof(user));
} }
var serialized = _jsonSerializer.SerializeToBytes(user); var serialized = JsonSerializer.SerializeToUtf8Bytes(user, _jsonOptions);
using (var connection = GetConnection()) using (var connection = GetConnection())
{ {
@ -142,7 +142,7 @@ namespace Emby.Server.Implementations.Data
throw new ArgumentNullException(nameof(user)); throw new ArgumentNullException(nameof(user));
} }
var serialized = _jsonSerializer.SerializeToBytes(user); var serialized = JsonSerializer.SerializeToUtf8Bytes(user, _jsonOptions);
using (var connection = GetConnection()) using (var connection = GetConnection())
{ {
@ -179,7 +179,7 @@ namespace Emby.Server.Implementations.Data
var id = row[0].ToInt64(); var id = row[0].ToInt64();
var guid = row[1].ReadGuidFromBlob(); var guid = row[1].ReadGuidFromBlob();
var user = _jsonSerializer.DeserializeFromString<User>(row.GetString(2)); var user = JsonSerializer.Deserialize<User>(row[2].ToBlob(), _jsonOptions);
user.InternalId = id; user.InternalId = id;
user.Id = guid; user.Id = guid;
return user; return user;

View File

@ -0,0 +1,20 @@
using System;
using System.Text.Json;
using System.Text.Json.Serialization;
namespace MediaBrowser.Common.Json.Converters
{
/// <summary>
/// Converts a GUID object or value to/from JSON.
/// </summary>
public class GuidConverter : JsonConverter<Guid>
{
/// <inheritdoc />
public override Guid Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
=> new Guid(reader.GetString());
/// <inheritdoc />
public override void Write(Utf8JsonWriter writer, Guid value, JsonSerializerOptions options)
=> writer.WriteStringValue(value);
}
}

View File

@ -0,0 +1,30 @@
using System.Text.Json;
using System.Text.Json.Serialization;
using MediaBrowser.Common.Json.Converters;
namespace MediaBrowser.Common.Json
{
/// <summary>
/// Helper class for having compatible JSON throughout the codebase.
/// </summary>
public static class JsonDefaults
{
/// <summary>
/// Gets the default <see cref="JsonSerializerOptions" /> options.
/// </summary>
/// <returns>The default <see cref="JsonSerializerOptions" /> options.</returns>
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;
}
}
}

View File

@ -14,6 +14,7 @@
<ItemGroup> <ItemGroup>
<PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="2.2.0" /> <PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="2.2.0" />
<PackageReference Include="Microsoft.Net.Http.Headers" Version="2.2.0" /> <PackageReference Include="Microsoft.Net.Http.Headers" Version="2.2.0" />
<PackageReference Include="System.Text.Json" Version="4.6.0" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>