Newtonsoft.Json对象转JSON字符串全集
需求:对象转为JSON字符串时可以同时满足以下5点。
1、同一个类中不同字段支持自定义日期格式,如:“2024-10-01”,“2024-10-01 12:12:12”;
2、string、datetime 为null时转为空字符串;int、decimal为null时转为0;对象为null时转为{};集合为null时转为[]; (PS:.Net8中Newtonsoft日期类型不支持空字符串)
3、long类型可以转为字符串;
4、枚举可以用“value、name、display” 做为json字符串的值;
5、小数点可以保留完整。
测试环境:
.Net5,.Net8
现实如下:
第1/3步:自定义ActionResult
public class CustomsJsonResult : ActionResult
{
public object Value { get; private set; }
public string ContentType { get; set; }
public CustomsJsonResult(object _value){
Value = _value;
}
/// <summary>
/// 时间默认格式
/// </summary>
public string formatter = "yyyy-MM-dd HH:mm:ss";
/// <summary>
///枚举转换
/// </summary>
public bool StringEnumConverter = false;
public override void ExecuteResult(ActionContext context)
{
if (context == null)
{
context.HttpContext.Response.WriteAsync("{}");
}
var response = context.HttpContext.Response;
response.ContentType = string.IsNullOrEmpty(ContentType) ? "application/json": ContentType;
var jsonSerizlizerSetting = new JsonSerializerSettings() {
//设置取消循环引用
MissingMemberHandling = MissingMemberHandling.Ignore,
ReferenceLoopHandling = ReferenceLoopHandling.Ignore,
//设置日期的格式为:yyyy-MM-dd
DateFormatString = formatter,
//自定义的解析协议
ContractResolver = new NullToEmptyStringResolver()
};
if (StringEnumConverter)
{
//转换枚举
CamelCaseNamingStrategy _CamelCaseNamingStrategy = new CamelCaseNamingStrategy { ProcessExtensionDataNames = true };
//转换时使用枚举jsonProperty [JsonConverter(typeof(EnumPropertyNameConverter)]
jsonSerizlizerSetting.Converters.Add(new Models.EnumPropertyNameConverter { });
//数字转为字符串 [JsonConverter(typeof(StringEnumConverter)]
jsonSerizlizerSetting.Converters.Add(new StringEnumConverter { NamingStrategy = _CamelCaseNamingStrategy });
}
//日期转换格式
jsonSerizlizerSetting.Converters.Add(new DateTimeFormat());//默认时间格式处理
jsonSerizlizerSetting.Converters.Add(new DateFormat());//默认时间格式处理
//时间转换格式
//long转为字符串
jsonSerizlizerSetting.Converters.Add(new Models.NumberToStrConverter { });
//jsonSerizlizerSetting.Converters.Add(new DecimalPrecisionConverter(6));
//序列化CardData出现内存溢出
var json = JsonConvert.SerializeObject(Value, Formatting.None, jsonSerizlizerSetting);
context.HttpContext.Response.WriteAsync(json);
}
}
第2/3步:自定义解析协议,这里主要实现null转换。
/// <summary>
/// JSON自定义解析协议
/// </summary>
public class NullToEmptyStringResolver : Newtonsoft.Json.Serialization.DefaultContractResolver
{
protected override IValueProvider CreateMemberValueProvider(System.Reflection.MemberInfo member)
{
if (member.MemberType == MemberTypes.Property)
{
var pi = (PropertyInfo)member;
if (
pi.PropertyType == typeof(string)
|| pi.PropertyType.BaseType == typeof(object)
|| pi.PropertyType == typeof(DateTime)
|| pi.PropertyType == typeof(DateTime?)
|| pi.PropertyType == typeof(decimal?)
)
{
return new NullableJsonValueProvider(pi);
}
}
return base.CreateMemberValueProvider(member);
}
}
// protected override IList<JsonProperty> CreateProperties(Type type, MemberSerialization memberSerialization)
// {
// return type.GetProperties()
// .Select(p => {
// var jp = base.CreateProperty(p, memberSerialization);
// jp.ValueProvider = new NullToEmptyStringValueProvider(p);
// return jp;
// }).ToList();
// }
//}
/// <summary>
///空值序列化提供程序
/// </summary>
public class NullableJsonValueProvider : IValueProvider
{
private static readonly string _defaultValue = string.Empty;
private readonly PropertyInfo _propertyInfo;
public NullableJsonValueProvider(PropertyInfo propertyInfo)
{
_propertyInfo = propertyInfo;
}
public void SetValue(object target, object value)
{
_propertyInfo.SetValue(target, value);
}
public object GetValue(object target)
{
var result = _propertyInfo.GetValue(target);
if (result != null)
{
return result;
}
if (_propertyInfo.PropertyType == typeof(string)
|| _propertyInfo.PropertyType == typeof(DateTime)
|| _propertyInfo.PropertyType == typeof(DateTime?)
)
{
//请注意,.Net8环境中Newtonsoft已经限制日期类型为空字符串,所以暂时放弃日期类型转为空字符串
return _defaultValue;
}
//decimal型转为0
else if (_propertyInfo.PropertyType == typeof(Nullable<decimal>))
return 0M;
//int型转为0
else if (_propertyInfo.PropertyType == typeof(Nullable<int>))
return 0;
//集合转为[]
else if (_propertyInfo.PropertyType.IsGenericType)
{
return new List<Newtonsoft.Json.Linq.JObject>(0);
}
//对象转为{}
else if (_propertyInfo.PropertyType.BaseType == typeof(object))
{
if (_propertyInfo.PropertyType != typeof(string) && result == null)
{
return new Newtonsoft.Json.Linq.JObject();
}
}
return result;
}
}
第3/3步:定义转换器
//yyyy-MM-dd日期的格式
public class DateFormat : JsonConverter
{
public string format = "yyyy-MM-dd";
public DateFormat()
{
}
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
if (value is DateTime dateTime)
{
writer.WriteValue(dateTime.ToString(format));
}
else
{
writer.WriteNull();
}
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
if (reader.TokenType == JsonToken.Null)
return null;
if (reader.TokenType == JsonToken.String)
{
string text = reader.Value.ToString();
if (DateTime.TryParse(text, out DateTime dateTime))
{
return dateTime;
}
}
throw new Exception($"Cannot convert {reader.TokenType} to {objectType}.");
}
public override bool CanConvert(Type objectType)
{
return objectType == typeof(DateTime);
}
}
//yyyy-MM-dd HH:mm:ss日期的格式
public class DateTimeFormat : JsonConverter
{
public string format = "yyyy-MM-dd HH:mm:ss";
public DateTimeFormat()
{
}
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
if (value is DateTime dateTime)
{
writer.WriteValue(dateTime.ToString(format));
}
else
{
writer.WriteNull();
}
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
if (reader.TokenType == JsonToken.Null)
return null;
if (reader.TokenType == JsonToken.String)
{
string text = reader.Value.ToString();
if (DateTime.TryParse(text, out DateTime dateTime))
{
return dateTime;
}
}
throw new Exception($"Cannot convert {reader.TokenType} to {objectType}.");
}
public override bool CanConvert(Type objectType)
{
return objectType == typeof(DateTime);
}
}
/// <summary>
/// 数字类型转为字符串
/// </summary>
public sealed class NumberToStrConverter : JsonConverter
{
/// <summary>
/// 转换成字符串的类型
/// </summary>
private readonly NumberConverterShip _ship;
/// <summary>
/// 大数据json序列化重写实例化
/// </summary>
public NumberToStrConverter()
{
_ship = (NumberConverterShip)0xFF;
}
/// <summary>
/// 大数据json序列化重写实例化
/// </summary>
/// <param name="ship">转换成字符串的类型</param>
public NumberToStrConverter(NumberConverterShip ship)
{
_ship = ship;
}
/// <inheritdoc />
/// <summary>
/// 确定此实例是否可以转换指定的对象类型。
/// </summary>
/// <param name="objectType">对象的类型。</param>
/// <returns>如果此实例可以转换指定的对象类型,则为:<c>true</c>,否则为:<c>false</c></returns>
public override bool CanConvert(Type objectType)
{
var typecode = Type.GetTypeCode(objectType.Name.Equals("Nullable`1") ? objectType.GetGenericArguments().First() : objectType);
switch (typecode)
{
case TypeCode.Int64:
return (_ship & NumberConverterShip.Int64) == NumberConverterShip.Int64;
// case TypeCode.Decimal:
// return (_ship & NumberConverterShip.Decimal) == NumberConverterShip.Decimal;
// case TypeCode.Double:
// return (_ship & NumberConverterShip.Double) == NumberConverterShip.Double;
// case TypeCode.UInt64:
// return (_ship & NumberConverterShip.UInt64) == NumberConverterShip.UInt64;
// case TypeCode.Single:
// return (_ship & NumberConverterShip.Single) == NumberConverterShip.Single;
default: return false;
}
}
/// <inheritdoc />
/// <summary>
/// 读取对象的JSON表示。
/// </summary>
/// <param name="reader">从 <see cref="T:Newtonsoft.Json.JsonReader" /> 中读取。</param>
/// <param name="objectType">对象的类型。</param>
/// <param name="existingValue">正在读取的对象的现有值。</param>
/// <param name="serializer">调用的序列化器实例。</param>
/// <returns>对象值。</returns>
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
if (reader.TokenType == JsonToken.Null)
{
return "";
}
return AsType(reader.Value.ToString(), objectType);
}
/// <summary>
/// 字符串格式数据转其他类型数据
/// </summary>
/// <param name="input">输入的字符串</param>
/// <param name="destinationType">目标格式</param>
/// <returns>转换结果</returns>
public static object AsType(string input, Type destinationType)
{
try
{
var converter = TypeDescriptor.GetConverter(destinationType);
if (converter.CanConvertFrom(typeof(string)))
{
return converter.ConvertFrom(null, null, input);
}
converter = TypeDescriptor.GetConverter(typeof(string));
if (converter.CanConvertTo(destinationType))
{
return converter.ConvertTo(null, null, input, destinationType);
}
}
catch
{
return null;
}
return null;
}
/// <inheritdoc />
/// <summary>
/// 写入对象的JSON表示形式。
/// </summary>
/// <param name="writer">要写入的 <see cref="T:Newtonsoft.Json.JsonWriter" /> 。</param>
/// <param name="value">要写入对象值</param>
/// <param name="serializer">调用的序列化器实例。</param>
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
if (value == null)
{
writer.WriteNull();
}
else
{
var objectType = value.GetType();
var typeCode = Type.GetTypeCode(objectType.Name.Equals("Nullable`1") ? objectType.GetGenericArguments().First() : objectType);
switch (typeCode)
{
case TypeCode.Int64:
writer.WriteValue(((long)value).ToString());
break;
//case TypeCode.Decimal:
// writer.WriteValue(((decimal)value).ToString("f6"));
// break;
// case TypeCode.Double:
// writer.WriteValue(((double)value).ToString("f4"));
// break;
// case TypeCode.Single:
// writer.WriteValue(((float)value).ToString("f2"));
// break;
// default:
// writer.WriteValue(value.ToString());
// break;
}
}
}
.Net MVC项目使用演示:
protected ActionResult Json(object data,string ContentType = "application/json", string formatter= "yyyy-MM-dd HH:mm:ss",bool StringEnumConverter=false) {
var res= new CustomsJsonResult(data)
{
ContentType = ContentType,
StringEnumConverter = StringEnumConverter,
formatter = formatter
};
return res;
}
其中的data就是我们要转为json字符串的数据 。