自定义 JsonConvertor,它还序列化其值减去其中一个属性



我在要求以特定方式序列化对象时遇到了问题,即对象id值成为键,对象的其余部分形成值。

要序列化的简化类:

[JsonConverter(typeof(FieldTypeConvertor))]
public class FieldType {
public string Id { get; set; }
public string Condition  { get; set; }
public string FieldType { get; set; }
public string Label { get; set; }
public string Options { get; set; }
}

这是我的JsonConvertorWriteJson方法:

public override void WriteJson(JsonWriter writer, UmbracoFormFieldDto value, JsonSerializer serializer)
{
var props = value.GetType().GetProperties();
var idProp = props.FirstOrDefault(p => p.Name.Equals("id", StringComparison.OrdinalIgnoreCase));
var key = idProp.GetValue(value, null).ToString();
var newObj = JsonConvert.SerializeObject(value, new JsonSerializerSettings()
{ ContractResolver = new IgnorePropertiesResolver(new[] { "id" }) });
var container = new JObject { { key, newObj } };
container.WriteTo(writer);
}

我明白为什么我最终会出现StackOverflow,但不知道如何避免它,以便生成我需要的输出,如下所示:

"idValueFromOriginalObj": {
"condition": "propValue",
"fieldype": "propValue",
"label": "propValue",
"options": "propValue"
}

从本质上讲,原始对象中id的值将成为序列化对象中的键,而原始对象的其余属性将形成该值。

您的问题是,在JsonConverter.ReadJson()内部,您试图递归序列化value对象,但由于转换器是使用[JsonConverter(typeof(TConverter))]直接应用于类型的,因此会出现堆栈溢出。

有几个选项可以禁用用于递归序列化的转换器JSON.Net在使用[JsonConvert((]时抛出StackOverflowException。但是,由于您已经使用自定义协定冲突解决程序IgnorePropertiesResolver来忽略名为"id"的属性,因此您可能会增强冲突解决程序,使其也可以忽略FieldTypeConvertor类型的转换器。以下应该可以做到:

public class IgnorePropertiesResolver : DefaultContractResolver
{
readonly HashSet<string> propertiesToIgnore;
readonly HashSet<Type> converterTypesToIgnore;
public IgnorePropertiesResolver(IEnumerable<string> propertiesToIgnore, IEnumerable<Type> converterTypesToIgnore) : base() =>
(this.propertiesToIgnore, this.converterTypesToIgnore) = 
((propertiesToIgnore ?? throw new ArgumentNullException()).ToHashSet(StringComparer.OrdinalIgnoreCase), 
(converterTypesToIgnore ?? throw new ArgumentNullException()).ToHashSet());

protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization)
{
var property = base.CreateProperty(member, memberSerialization);
if (propertiesToIgnore.Contains(member.Name))
property.Ignored = true;
if (property.Converter != null && converterTypesToIgnore.Contains(property.Converter.GetType()))
property.Converter = null;
return property;
}
protected override JsonContract CreateContract(Type objectType)
{
var contract = base.CreateContract(objectType);
if (contract.Converter != null && converterTypesToIgnore.Contains(contract.Converter.GetType()))
contract.Converter = null;
return contract;
}
};

然后修改FieldTypeConvertor如下:

public sealed class FieldTypeConvertor : JsonConverter<UmbracoFormFieldDto>
{
static readonly IContractResolver innerResolver = new IgnorePropertiesResolver(new [] { "id" }, new [] { typeof(FieldTypeConvertor) })
{
NamingStrategy = new CamelCaseNamingStrategy(),
};
public override void WriteJson(JsonWriter writer, UmbracoFormFieldDto value, JsonSerializer serializer)
{
var props = value.GetType().GetProperties();
var idProp = props.FirstOrDefault(p => p.Name.Equals("id", StringComparison.OrdinalIgnoreCase));
var key = idProp.GetValue(value, null).ToString();
writer.WriteStartObject();
writer.WritePropertyName(key);
JsonSerializer.CreateDefault(new JsonSerializerSettings { ContractResolver = innerResolver }).Serialize(writer, value);
writer.WriteEndObject();
}
public override UmbracoFormFieldDto ReadJson(JsonReader reader, Type objectType, UmbracoFormFieldDto existingValue, bool hasExistingValue, JsonSerializer serializer) => throw new NotImplementedException();
}

您的模型将根据需要进行序列化:

{
"idValueFromOriginalObj": {
"condition": "propValue",
"fieldType": "propValue",
"label": "propValue",
"options": "propValue"
}
}

注:

  • Newtonsoft建议您缓存合约解析器以获得最佳性能。

  • 您应该从DefaultContractResolver而不是CamelCasePropertyNamesContractResolver继承,原因在Json.Net:Html Helper方法未重新生成中有说明。

  • 出于性能原因,我取消了对JObject的中间序列化,而是直接序列化到传入的JsonWriter

在这里演示小提琴。

相关内容

  • 没有找到相关文章

最新更新