Files
zszq-trs/Framework/YLErp.Core/Helpers/JsonHelper.cs
T

367 lines
12 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using Newtonsoft.Json.Serialization;
using YLErp.Commons;
using YLErp.Helpers;
namespace System
{
/// <summary>
/// JSON序列化/反序列化帮助类(使用json.net)
/// </summary>
public static class JsonHelper
{
/// <summary>
/// 将JSON字符串反序列化为对象,如果json字符串为null或空字符串,返回default(T)
/// </summary>
public static T ToObject<T>(string json)
{
return string.IsNullOrWhiteSpace(json) ? default : JsonConvert.DeserializeObject<T>(json, settings[(int)SerializeSetting.all]);
}
/// <summary>
/// 将JSON字符串反序列化为对象,如果json字符串为null或空字符串,返回default(T)
/// </summary>
public static T Parse<T>(string json)
{
return string.IsNullOrWhiteSpace(json) ? default : JsonConvert.DeserializeObject<T>(json, settings[(int)SerializeSetting.all]);
}
/// <summary>
/// 将JSON字符串反序列化为对象,如果json字符串为null或空字符串,返回default(T)
/// </summary>
public static T Deserialize<T>(string json)
{
return string.IsNullOrWhiteSpace(json) ? default : JsonConvert.DeserializeObject<T>(json, settings[(int)SerializeSetting.all]);
}
public static T DeserializeIgnoreNull<T>(string json)
{
var settings = new JsonSerializerSettings
{
Error = (obj, args2) =>
{
args2.ErrorContext.Handled = true;
}
};
return string.IsNullOrWhiteSpace(json) ? default : JsonConvert.DeserializeObject<T>(json, settings);
}
//---------------------------------------------------------------------------------
/// <summary>
/// 将对象序列化为JSON格式,如果对象为null,返回string.empty
/// </summary>
public static string ToJson(this object obj, bool ignoreNullValue = true, bool camelCase = false)
{
if (obj == null)
{
return string.Empty;
}
if (obj is Collections.Specialized.NameValueCollection nv)
{
obj = nv.AllKeys.ToDictionary(k => k, k => nv[k]);
}
else if (obj is IEnumerable<object> arr && arr.Count() == 0)
{
return "[]";
}
var setting = SerializeSetting.none;
if (ignoreNullValue)
{
setting = SerializeSetting.ignoreNull;
}
if (camelCase)
{
setting |= SerializeSetting.camelCase;
}
return JsonConvert.SerializeObject(obj, settings[(int)setting]);
}
/// <summary>
/// 将对象序列化为JSON格式,如果对象为null,返回string.empty
/// </summary>
public static string Stringify(object obj, bool ignoreNullValue = true, bool camelCase = false)
{
return ToJson(obj, ignoreNullValue, camelCase);
}
/// <summary>
/// 将对象序列化为JSON格式,如果对象为null,返回string.empty
/// </summary>
public static string Serialize(object obj, bool ignoreNullValue = true, bool camelCase = false)
{
return ToJson(obj, ignoreNullValue, camelCase);
}
/// <summary>
/// 序列化为可安全内嵌进 &lt;script&gt; 的 JSONHTML 敏感字符(&lt; &gt; &amp; 等)以 \uXXXX 形式转义,
/// 供 Razor 页 @Html.Raw(obj.ToInlineJson()) 内联页面对象使用。
/// 背景:全局 AntiXssConverterYLErpWeb Program.cs 注册)在 @Json.Serialize 渲染时把 &lt; &gt; 实体编码为 &amp;lt; &amp;gt;
/// JS 侧拿到的是实体文本而非原值(如 SpanConfig.BondTerm "&lt;5y" 变 "&amp;lt;5y"),保存回写即脏数据。
/// </summary>
public static string ToInlineJson(this object obj, bool ignoreNullValue = false)
{
if (obj == null)
{
return "null";
}
var setting = ((JsonSerializerSettingsEx)(ignoreNullValue ? settings[(int)SerializeSetting.ignoreNull] : settings[(int)SerializeSetting.none])).Clone();
setting.StringEscapeHandling = StringEscapeHandling.EscapeHtml;
return JsonConvert.SerializeObject(obj, setting);
}
//---------------------------------------------------------------------------------
/// <summary>
///
/// </summary>
public static JsonSerializerSettings GetDefaultSettings()
{
var setting = new JsonSerializerSettings
{
ReferenceLoopHandling = ReferenceLoopHandling.Ignore
};
setting.Converters.Insert(0, DateOnlyJsonConverter.Default);
return setting;
}
//---------------------------------------------------------------------------------
static readonly JsonSerializerSettings[] settings;
static JsonHelper()
{
settings = new JsonSerializerSettings[1 + (int)SerializeSetting.all];
var defaultSettings = new JsonSerializerSettingsEx();
settings[(int)SerializeSetting.none] = defaultSettings;
settings[(int)SerializeSetting.ignoreNull] = defaultSettings.Clone().Set(n => n.NullValueHandling = NullValueHandling.Ignore);
settings[(int)SerializeSetting.camelCase] = defaultSettings.Clone().Set(n => n.ContractResolver = new CamelCasePropertyNamesContractResolver());
settings[(int)(SerializeSetting.ignoreNull | SerializeSetting.camelCase)] = defaultSettings.Clone().Set(n =>
{
n.NullValueHandling = NullValueHandling.Ignore;
n.ContractResolver = new CamelCasePropertyNamesContractResolver();
});
foreach (var s in settings)
{
if (s.Converters != null)
{
s.Converters.Insert(0, DateOnlyJsonConverter.Default);
}
else
{
s.Converters = new List<JsonConverter> { DateOnlyJsonConverter.Default };
}
}
}
class JsonSerializerSettingsEx : JsonSerializerSettings
{
public JsonSerializerSettingsEx()
{
DateFormatString = "yyyy-MM-dd HH:mm:ss";
ReferenceLoopHandling = ReferenceLoopHandling.Ignore;
}
public JsonSerializerSettingsEx Set(Action<JsonSerializerSettingsEx> setter)
{
setter(this);
return this;
}
public JsonSerializerSettingsEx Clone()
{
return (JsonSerializerSettingsEx)MemberwiseClone();
}
}
/// <summary>
/// json序列化配置枚举
/// </summary>
enum SerializeSetting
{
none = 0,
ignoreNull = 1,
camelCase = 2,
all = ignoreNull | camelCase
}
}
/// <summary>
/// 支持解析单个或数组格式到集合
/// 在IEnumerable[T]泛型定义的字段上加JsonConverterAttribute
/// [JsonConverter(typeof(SingleOrArrayConverter<string>))]
/// </summary>
public class SingleOrArrayConverter<T> : JsonConverter
{
public override bool CanConvert(Type objectType)
{
return objectType == typeof(IEnumerable<T>);
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
var token = JToken.Load(reader);
if (token.Type == JTokenType.Array)
{
return token.ToObject<T[]>();
}
return new T[] { token.ToObject<T>() };
}
public override bool CanWrite
{
get { return false; }
}
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
throw new NotImplementedException();
}
}
/// <summary>
/// 支持解析单个或数组格式到集合(空字符串将被过滤掉)
/// </summary>
public class StringArrayConverter : SingleOrArrayConverter<string>
{
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
var token = JToken.Load(reader);
if (token.Type == JTokenType.Array)
{
return token.ToObject<string[]>().Where(n => !string.IsNullOrWhiteSpace(n)).ToArray();
}
var str = token.ToObject<string>();
return string.IsNullOrWhiteSpace(str) ? Array.Empty<string>() : new[] { str };
}
}
/// <summary>
///
/// </summary>
class DateOnlyJsonConverter : JsonConverter
{
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
writer.WriteValue(value?.ToString());
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
var nullable = ReflectionHelper.IsNullableType(objectType);
if (reader.TokenType == JsonToken.Null)
{
if (nullable)
{
return null;
}
return new YcDateOnly(DateTime.MinValue);
}
if (reader.TokenType == JsonToken.Date)
{
return new YcDateOnly((DateTime)reader.Value);
}
if (reader.TokenType != JsonToken.String)
{
throw new JsonSerializationException($"Unexpected token parsing date. Expected String, got {reader.TokenType},value:{reader.Value}");
}
var dateText = reader.Value?.ToString();
if (string.IsNullOrWhiteSpace(dateText))
{
if (nullable)
{
return null;
}
return DateTime.MinValue;
}
var dt = DateTime.Parse(dateText, Globalization.CultureInfo.InvariantCulture);
return new YcDateOnly(dt);
}
public override bool CanRead => true;
public override bool CanConvert(Type objectType)
{
return objectType == typeof(YcDateOnly) || objectType == typeof(YcDateOnly?);
}
public static readonly DateOnlyJsonConverter Default;
static DateOnlyJsonConverter()
{
Default = new DateOnlyJsonConverter();
}
}
/// <summary>
/// 用于格式化double数据
/// </summary>
public class DoubleJsonWriteConverter : JsonConverter
{
readonly OtcFormatOption _format;
public DoubleJsonWriteConverter(int minDecimals, int maxDecimals)
{
if (minDecimals < 0)
{
minDecimals = 0;
}
if (maxDecimals < minDecimals)
{
maxDecimals = minDecimals;
}
_format = new OtcFormatOption
{
minDecimals = minDecimals,
maxDecimals = maxDecimals,
grouping = false,
percent = false,
rounded = true
};
}
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
if (value == null)
{
writer.WriteNull();
}
else if (value is double d)
{
writer.WriteValue(_format.FormatValue(d));
}
else
{
var d2 = (double?)value;
writer.WriteValue(_format.FormatValue(d2.Value));
}
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
throw new NotImplementedException();
}
public override bool CanRead => false;
public override bool CanConvert(Type objectType)
{
return objectType == typeof(double) || objectType == typeof(double?);
}
}
}