Skip to content

Commit

Permalink
Merge pull request #262 from MartinYl/dev
Browse files Browse the repository at this point in the history
扩展EasyCaching.Serialization.System.Text.Json,使用System.Text.Json进行序列化和反序列化json
  • Loading branch information
catcherwong authored Nov 18, 2020
2 parents b45674e + 596874b commit 5e95d56
Show file tree
Hide file tree
Showing 9 changed files with 429 additions and 1 deletion.
7 changes: 7 additions & 0 deletions EasyCaching.sln
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "bus", "bus", "{B337509B-75F
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "EasyCaching.LiteDB", "src\EasyCaching.LiteDB\EasyCaching.LiteDB.csproj", "{BA850294-3103-4540-8A27-FC768E1DC8FC}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "EasyCaching.Serialization.SystemTextJson", "serialization\EasyCaching.Serialization.SystemTextJson\EasyCaching.Serialization.SystemTextJson.csproj", "{4FCF16BF-5E21-4B74-AB45-3C121ADF1485}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Expand Down Expand Up @@ -178,6 +180,10 @@ Global
{BA850294-3103-4540-8A27-FC768E1DC8FC}.Debug|Any CPU.Build.0 = Debug|Any CPU
{BA850294-3103-4540-8A27-FC768E1DC8FC}.Release|Any CPU.ActiveCfg = Release|Any CPU
{BA850294-3103-4540-8A27-FC768E1DC8FC}.Release|Any CPU.Build.0 = Release|Any CPU
{4FCF16BF-5E21-4B74-AB45-3C121ADF1485}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{4FCF16BF-5E21-4B74-AB45-3C121ADF1485}.Debug|Any CPU.Build.0 = Debug|Any CPU
{4FCF16BF-5E21-4B74-AB45-3C121ADF1485}.Release|Any CPU.ActiveCfg = Release|Any CPU
{4FCF16BF-5E21-4B74-AB45-3C121ADF1485}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
Expand Down Expand Up @@ -209,6 +215,7 @@ Global
{43AD80E9-696B-4042-9D50-B26F48BE1928} = {A0F5CC7E-155F-4726-8DEB-E966950B3FE9}
{711603E1-8363-4F8D-9AA9-8C03EC8BD35F} = {B4241D34-A973-4A13-BD89-9BAE3F2BDDF6}
{BA850294-3103-4540-8A27-FC768E1DC8FC} = {A0F5CC7E-155F-4726-8DEB-E966950B3FE9}
{4FCF16BF-5E21-4B74-AB45-3C121ADF1485} = {15070C49-A507-4844-BCFE-D319CFBC9A63}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {63A57886-054B-476C-AAE1-8D7C8917682E}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
using System;
using System.Collections.Generic;
using System.Text.Encodings.Web;
using System.Text.Json;
using System.Text.Json.Serialization;

namespace EasyCaching.Serialization.SystemTextJson.Configurations
{
public class EasyCachingJsonSerializerOptions
{
/// <summary>
/// Gets or sets the encoder to use when escaping strings, or null to use the default
/// encoder.
/// </summary>
public JavaScriptEncoder Encoder => JavaScriptEncoder.UnsafeRelaxedJsonEscaping;
/// <summary>
/// Gets or sets a value that defines how comments are handled during deserialization.
/// </summary>
public JsonCommentHandling ReadCommentHandling => JsonCommentHandling.Disallow;
/// <summary>
/// Gets or sets a value that specifies the policy used to convert a property's name
/// on an object to another format, such as camel-casing, or null to leave property
/// names unchanged.
/// </summary>
public JsonNamingPolicy PropertyNamingPolicy => null;
/// <summary>
/// Gets or sets a value that determines whether a property's name uses a case-insensitive
/// comparison during deserialization. The default value is false.
/// </summary>
public bool PropertyNameCaseInsensitive => false;
/// <summary>
/// Specifies how number types should be handled when serializing or deserializing.
/// </summary>
public JsonNumberHandling NumberHandling => JsonNumberHandling.Strict;
/// <summary>
/// Gets or sets the maximum depth allowed when serializing or deserializing JSON,
/// with the default value of 0 indicating a maximum depth of 64.
/// </summary>
public int MaxDepth => 0;
/// <summary>
/// Determines whether fields are handled serialization and deserialization. The
/// default value is false.
/// </summary>
public bool IncludeFields => false;
/// <summary>
/// Gets a value that determines whether read-only properties are ignored during
/// serialization. The default value is false.
/// </summary>
public bool IgnoreReadOnlyProperties => false;
/// <summary>
/// Determines whether read-only fields are ignored during serialization. A property
/// is read-only if it isn't marked with the readonly keyword. The default value is false.
/// </summary>
public bool IgnoreReadOnlyFields => false;
/// <summary>
/// Gets or sets a value that determines whether null values are ignored during serialization
/// and deserialization. The default value is false.
/// </summary>
public bool IgnoreNullValues = false;
/// <summary>
/// Gets or sets the policy used to convert a System.Collections.IDictionary key's
/// name to another format, such as camel-casing.
/// </summary>
public JsonNamingPolicy DictionaryKeyPolicy => null;
/// <summary>
/// Specifies a condition to determine when properties with default values are ignored
/// during serialization or deserialization. The default value is System.Text.Json.Serialization.JsonIgnoreCondition.Never.
/// </summary>
public JsonIgnoreCondition DefaultIgnoreCondition => JsonIgnoreCondition.Never;
/// <summary>
/// Gets or sets the default buffer size, in bytes, to use when creating temporary buffers.
/// </summary>
public int DefaultBufferSize => 16 * 1024;
/// <summary>
/// Gets the list of user-defined converters that were registered.
/// </summary>
public IList<JsonConverter> Converters => new List<JsonConverter>();
/// <summary>
/// Get or sets a value that indicates whether an extra comma at the end of a list
/// of JSON values in an object or array is allowed (and ignored) within the JSON
/// payload being deserialized.
/// </summary>
public bool AllowTrailingCommas => false;
/// <summary>
/// Configures how object references are handled when reading and writing JSON.
/// </summary>
public ReferenceHandler ReferenceHandler => null;
/// <summary>
/// Gets or sets a value that defines whether JSON should use pretty printing. By
/// default, JSON is serialized without any extra white space.
/// </summary>
public bool WriteIndented => false;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
using EasyCaching.Core.Configurations;
using System;
using System.Linq;
using System.Text.Json;

namespace EasyCaching.Serialization.SystemTextJson.Configurations
{

/// <summary>
/// EasyCaching options extensions.
/// </summary>
public static class EasyCachingOptionsExtensions
{
/// <summary>
/// Withs the json serializer.
/// </summary>
/// <param name="options">Options.</param>
/// <param name="name">The name of this serializer instance.</param>
public static EasyCachingOptions WithSystemTextJson(this EasyCachingOptions options, string name = "json") => options.WithSystemTextJson(configure: x => { }, name);

/// <summary>
/// Withs the json serializer.
/// </summary>
/// <param name="options">Options.</param>
/// <param name="configure">Configure serializer settings.</param>
/// <param name="name">The name of this serializer instance.</param>
public static EasyCachingOptions WithSystemTextJson(this EasyCachingOptions options, Action<EasyCachingJsonSerializerOptions> configure, string name)
{
var easyCachingJsonSerializerOptions = new EasyCachingJsonSerializerOptions();

configure(easyCachingJsonSerializerOptions);

void jsonSerializerSettings(JsonSerializerOptions x)
{
x.MaxDepth = easyCachingJsonSerializerOptions.MaxDepth;
x.AllowTrailingCommas = easyCachingJsonSerializerOptions.AllowTrailingCommas;
x.Converters.Union(easyCachingJsonSerializerOptions.Converters);
x.DefaultBufferSize = easyCachingJsonSerializerOptions.DefaultBufferSize;
x.DefaultIgnoreCondition = easyCachingJsonSerializerOptions.DefaultIgnoreCondition;
x.DictionaryKeyPolicy = easyCachingJsonSerializerOptions.DictionaryKeyPolicy;
x.Encoder = easyCachingJsonSerializerOptions.Encoder;
x.IgnoreReadOnlyFields = easyCachingJsonSerializerOptions.IgnoreReadOnlyFields;
x.IgnoreReadOnlyProperties = easyCachingJsonSerializerOptions.IgnoreReadOnlyProperties;
x.IncludeFields = easyCachingJsonSerializerOptions.IncludeFields;
x.NumberHandling = easyCachingJsonSerializerOptions.NumberHandling;
x.PropertyNameCaseInsensitive = easyCachingJsonSerializerOptions.PropertyNameCaseInsensitive;
x.PropertyNamingPolicy = easyCachingJsonSerializerOptions.PropertyNamingPolicy;
x.ReadCommentHandling = easyCachingJsonSerializerOptions.ReadCommentHandling;
x.ReferenceHandler = easyCachingJsonSerializerOptions.ReferenceHandler;
x.WriteIndented = easyCachingJsonSerializerOptions.WriteIndented;
}

options.RegisterExtension(new JsonOptionsExtension(name, jsonSerializerSettings));

return options;
}

/// <summary>
/// Withs the json serializer.
/// </summary>
/// <param name="options">Options.</param>
/// <param name="jsonSerializerSettingsConfigure">Configure serializer settings.</param>
/// <param name="name">The name of this serializer instance.</param>
public static EasyCachingOptions WithSystemTextJson(this EasyCachingOptions options, Action<JsonSerializerOptions> jsonSerializerSettingsConfigure, string name)
{
options.RegisterExtension(new JsonOptionsExtension(name, jsonSerializerSettingsConfigure));

return options;
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
using EasyCaching.Core.Configurations;
using EasyCaching.Core.Serialization;
using Microsoft.Extensions.DependencyInjection;
using System;
using System.Text.Json;

namespace EasyCaching.Serialization.SystemTextJson
{
/// <summary>
/// Json options extension.
/// </summary>
internal sealed class JsonOptionsExtension : IEasyCachingOptionsExtension
{
/// <summary>
/// The name.
/// </summary>
private readonly string _name;

/// <summary>
/// The configure.
/// </summary>
private readonly Action<JsonSerializerOptions> _configure;

/// <summary>
/// Initializes a new instance of the <see cref="T:EasyCaching.Serialization.SystemTextJson.JsonOptionsExtension"/> class.
/// </summary>
/// <param name="name">Name.</param>
/// <param name="configure">Configure.</param>
public JsonOptionsExtension(string name, Action<JsonSerializerOptions> configure)
{
_name = name;
_configure = configure;
}

public void AddServices(IServiceCollection services)
{
Action<JsonSerializerOptions> configure = x => { };

if (_configure != null) configure = _configure;

services.AddOptions();
services.Configure(_name, configure);
services.AddSingleton<IEasyCachingSerializer, DefaultJsonSerializer>(x =>
{
var optionsMon = x.GetRequiredService<Microsoft.Extensions.Options.IOptionsMonitor<JsonSerializerOptions>>();
var options = optionsMon.Get(_name);
return new DefaultJsonSerializer(_name, options);
});
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
using EasyCaching.Core.Internal;
using EasyCaching.Core.Serialization;
using System;
using System.IO;
using System.Text;
using System.Text.Json;

namespace EasyCaching.Serialization.SystemTextJson
{
/// <summary>
/// Default json serializer.
/// </summary>
public class DefaultJsonSerializer : IEasyCachingSerializer
{
/// <summary>
/// The json serializer.
/// </summary>
private readonly JsonSerializerOptions jsonSerializerOption;
/// <summary>
/// The name.
/// </summary>
private readonly string _name;
/// <summary>
/// Gets the name.
/// </summary>
/// <value>The name.</value>
public string Name => _name;

/// <summary>
/// Initializes a new instance of the <see cref="T:EasyCaching.Serialization.SystemTextJson.DefaultJsonSerializer"/> class.
/// </summary>
/// <param name="name">Name.</param>
/// <param name="serializerSettings">serializerSettings.</param>
public DefaultJsonSerializer(string name, JsonSerializerOptions serializerSettings)
{
_name = name;
jsonSerializerOption = serializerSettings;
}

/// <summary>
/// Deserialize the specified bytes.
/// </summary>
/// <returns>The deserialize.</returns>
/// <param name="bytes">Bytes.</param>
/// <typeparam name="T">The 1st type parameter.</typeparam>
public T Deserialize<T>(byte[] bytes)
{
return JsonSerializer.Deserialize<T>(bytes, jsonSerializerOption);
}
/// <summary>
/// Deserialize the specified bytes.
/// </summary>
/// <returns>The deserialize.</returns>
/// <param name="bytes">Bytes.</param>
/// <param name="type">Type.</param>
public object Deserialize(byte[] bytes, Type type)
{
return JsonSerializer.Deserialize(bytes, type, jsonSerializerOption);
}
/// <summary>
/// Deserializes the object.
/// </summary>
/// <returns>The object.</returns>
/// <param name="value">Value.</param>
public object DeserializeObject(ArraySegment<byte> value)
{
var jr = new Utf8JsonReader(value);
jr.Read();
if (jr.TokenType == JsonTokenType.StartArray)
{
jr.Read();
var typeName = Encoding.UTF8.GetString(jr.ValueSpan.ToArray());
var type = Type.GetType(typeName, throwOnError: true);

jr.Read();
return JsonSerializer.Deserialize(ref jr, type, jsonSerializerOption);
}
else
{
throw new InvalidDataException("JsonTranscoder only supports [\"TypeName\", object]");
}
}
/// <summary>
//; Serialize the specified value.
/// </summary>
/// <returns>The serialize.</returns>
/// <param name="value">Value.</param>
/// <typeparam name="T">The 1st type parameter.</typeparam>
public byte[] Serialize<T>(T value)
{
return JsonSerializer.SerializeToUtf8Bytes(value, jsonSerializerOption);
}
/// <summary>
/// Serializes the object.
/// </summary>
/// <returns>The object.</returns>
/// <param name="obj">Object.</param>
public ArraySegment<byte> SerializeObject(object obj)
{
var typeName = TypeHelper.BuildTypeName(obj.GetType());

using (var ms = new MemoryStream())
using (var jw = new Utf8JsonWriter(ms))
{
jw.WriteStartArray();
jw.WriteStringValue(typeName);

JsonSerializer.Serialize(jw, obj, jsonSerializerOption);

jw.WriteEndArray();

jw.Flush();

return new ArraySegment<byte>(ms.ToArray(), 0, (int)ms.Length);
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="System.Text.Json" Version="5.0.0" />
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\..\src\EasyCaching.Core\EasyCaching.Core.csproj" />
</ItemGroup>

</Project>
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,6 @@ public void TrySet_Parallel_Should_Succeed()
});

Assert.Equal(1, list.Count(x => x));

}

[Fact]
Expand Down
1 change: 1 addition & 0 deletions test/EasyCaching.UnitTests/EasyCaching.UnitTests.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@
<ProjectReference Include="..\..\serialization\EasyCaching.Serialization.Json\EasyCaching.Serialization.Json.csproj" />
<ProjectReference Include="..\..\serialization\EasyCaching.Serialization.MessagePack\EasyCaching.Serialization.MessagePack.csproj" />
<ProjectReference Include="..\..\serialization\EasyCaching.Serialization.Protobuf\EasyCaching.Serialization.Protobuf.csproj" />
<ProjectReference Include="..\..\serialization\EasyCaching.Serialization.SystemTextJson\EasyCaching.Serialization.SystemTextJson.csproj" />
<ProjectReference Include="..\..\src\EasyCaching.Core\EasyCaching.Core.csproj" />
<ProjectReference Include="..\..\src\EasyCaching.LiteDB\EasyCaching.LiteDB.csproj" />
<ProjectReference Include="..\..\src\EasyCaching.Memcached\EasyCaching.Memcached.csproj" />
Expand Down
Loading

0 comments on commit 5e95d56

Please sign in to comment.