350 lines
11 KiB
C#
350 lines
11 KiB
C#
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>
|
|
///
|
|
/// </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?);
|
|
}
|
|
}
|
|
}
|