忽略序列化为JSON时引发异常的类成员

我正在使用Newtonsoft JSON序列化程序,它适用于大多数对象。

不幸的是,JsonSerializationException当我尝试序列化一个大对象时,我得到了一个,其中一个成员抛出NullReferenceException

无论如何,有没有要忽略有问题的成员并序列化对象的其余部分?

我在想JsonSerializerSettings吗?

这是我想要做的简化版本:

private class TestExceptionThrowingClass

{

public string Name { get { return "The Name"; } }

public string Address { get { throw new NullReferenceException(); } }

public int Age { get { return 30; } }

}

[Test]

public void CanSerializeAClassWithAnExceptionThrowingMember()

{

// Arrange

var toSerialize = new TestExceptionThrowingClass();

// Act

var serializerSettings = new Newtonsoft.Json.JsonSerializerSettings();

serializerSettings.MaxDepth = 5;

serializerSettings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore;

serializerSettings.MissingMemberHandling = Newtonsoft.Json.MissingMemberHandling.Ignore;

serializerSettings.NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore;

serializerSettings.ObjectCreationHandling = Newtonsoft.Json.ObjectCreationHandling.Reuse;

serializerSettings.DefaultValueHandling = Newtonsoft.Json.DefaultValueHandling.Ignore;

var result = Newtonsoft.Json.JsonConvert.SerializeObject(toSerialize);

// Assert

Assert.That(result, Is.EqualTo(@"{""Name"":""The Name"",""Age"":30}"));

}

这是堆栈跟踪:

at Newtonsoft.Json.Serialization.DynamicValueProvider.GetValue(Object target) 

at Newtonsoft.Json.Serialization.JsonSerializerInternalWriter.CalculatePropertyValues(JsonWriter writer, Object value, JsonContainerContract contract, JsonProperty member, JsonProperty property, JsonContract& memberContract, Object& memberValue)

at Newtonsoft.Json.Serialization.JsonSerializerInternalWriter.SerializeObject(JsonWriter writer, Object value, JsonObjectContract contract, JsonProperty member, JsonContainerContract collectionContract, JsonProperty containerProperty)

at Newtonsoft.Json.Serialization.JsonSerializerInternalWriter.SerializeValue(JsonWriter writer, Object value, JsonContract valueContract, JsonProperty member, JsonContainerContract containerContract, JsonProperty containerProperty)

at Newtonsoft.Json.Serialization.JsonSerializerInternalWriter.Serialize(JsonWriter jsonWriter, Object value, Type objectType)

at Newtonsoft.Json.JsonSerializer.SerializeInternal(JsonWriter jsonWriter, Object value, Type objectType)

at Newtonsoft.Json.JsonConvert.SerializeObject(Object value, Type type, Formatting formatting, JsonSerializerSettings settings)

at Newtonsoft.Json.JsonConvert.SerializeObject(Object value)

at AspectsProject.Aspects.CachingPolicy.CachingPolicyCacheKeyCreatorTests.CanSerializeAClassWithAnExceptionThrowingMember() in D:\Dev\test.cs:line 169

--NullReferenceException

at AspectsProject.Aspects.CachingPolicy.CachingPolicyCacheKeyCreatorTests.TestExceptionThrowingClass.get_Address() in D:\Dev\test.cs:line 149

at GetAddress(Object )

at Newtonsoft.Json.Serialization.DynamicValueProvider.GetValue(Object target)

如果有人知道可以执行此操作,我很乐意使用其他JSON序列化程序。

回答:

如果您不控制源代码,则可以ContractResolver在序列化过程中使用自定义为有问题的属性注入“

ShouldSerialize”方法。您可以使该方法始终返回false,或者可以选择实现一些逻辑,该逻辑将检测属性将仅在这种情况下抛出并返回false的情况。

例如,假设您的类如下所示:

class Problematic

{

public int Id { get; set; }

public string Name { get; set; }

public object Offender

{

get { throw new NullReferenceException(); }

}

}

显然,如果我们尝试序列化上述内容,它将无法正常工作,因为Offender当序列化程序尝试访问该属性时,该属性始终会引发异常。由于我们知道引起问题的类和属性名称,因此我们可以编写一个自定义ContractResolver(派生自DefaultContractResolver)来抑制该特定成员的序列化。

class CustomResolver : DefaultContractResolver

{

protected override JsonProperty CreateProperty(MemberInfo member,

MemberSerialization memberSerialization)

{

JsonProperty property = base.CreateProperty(member, memberSerialization);

if (property.DeclaringType == typeof(Problematic) &&

property.PropertyName == "Offender")

{

property.ShouldSerialize = instanceOfProblematic => false;

}

return property;

}

}

这是演示如何使用它的演示:

class Program

{

static void Main(string[] args)

{

Problematic obj = new Problematic

{

Id = 1,

Name = "Foo"

};

JsonSerializerSettings settings = new JsonSerializerSettings();

settings.ContractResolver = new CustomResolver();

string json = JsonConvert.SerializeObject(obj, settings);

Console.WriteLine(json);

}

}

输出:

{"Id":1,"Name":"Foo"}

回答:

在您的评论中,您指出了当访问任何属性时,您可能会抛出多种异常的对象。为此,我们需要更通用的东西。这是一个可能适用于这种情况的解析器,但是您需要在自己的环境中进行广泛的测试。它不依赖于任何特定的类或属性名称,而是为

每个 以其方式出现的属性创建ShouldSerialize谓词。在该谓词中,它使用反射来获取try /

catch内的属性的值。如果成功,则返回true,否则返回false。

class CustomResolver : DefaultContractResolver

{

protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization)

{

JsonProperty property = base.CreateProperty(member, memberSerialization);

property.ShouldSerialize = instance =>

{

try

{

PropertyInfo prop = (PropertyInfo)member;

if (prop.CanRead)

{

prop.GetValue(instance, null);

return true;

}

}

catch

{

}

return false;

};

return property;

}

}

这是一个演示:

class Program

{

static void Main(string[] args)

{

List<MightThrow> list = new List<MightThrow>

{

new MightThrow { Flags = ThrowFlags.None, Name = "none throw" },

new MightThrow { Flags = ThrowFlags.A, Name = "A throws" },

new MightThrow { Flags = ThrowFlags.B, Name = "B throws" },

new MightThrow { Flags = ThrowFlags.Both, Name = "both throw" },

};

JsonSerializerSettings settings = new JsonSerializerSettings();

settings.ContractResolver = new CustomResolver();

settings.Formatting = Formatting.Indented;

string json = JsonConvert.SerializeObject(list, settings);

Console.WriteLine(json);

}

}

[Flags]

enum ThrowFlags

{

None = 0,

A = 1,

B = 2,

Both = 3

}

class MightThrow

{

public string Name { get; set; }

public ThrowFlags Flags { get; set; }

public string A

{

get

{

if ((Flags & ThrowFlags.A) == ThrowFlags.A)

throw new Exception();

return "a";

}

}

public string B

{

get

{

if ((Flags & ThrowFlags.B) == ThrowFlags.B)

throw new Exception();

return "b";

}

}

}

输出:

[

{

"Name": "none throw",

"Flags": 0,

"A": "a",

"B": "b"

},

{

"Name": "A throws",

"Flags": 1,

"B": "b"

},

{

"Name": "B throws",

"Flags": 2,

"A": "a"

},

{

"Name": "both throw",

"Flags": 3

}

]

以上是 忽略序列化为JSON时引发异常的类成员 的全部内容, 来源链接: utcz.com/qa/406332.html

回到顶部