【问题标题】:Is it possible to configure Newtonsoft.Json to ignore propreties with [ScriptIgnore] attribute是否可以将 Newtonsoft.Json 配置为忽略具有 [ScriptIgnore] 属性的属性
【发布时间】:2019-04-17 18:07:57
【问题描述】:

我有一个第三方类(我们称之为Class1),我需要将其序列化为 JSON。如果我尝试按原样执行此操作,我将收到 StackOverflowExceptionJsonSerializationException 消息“检测到类型的自引用循环”。我尝试为JsonConvert 应用以​​下设置,但它并没有帮助我避免StackOverflowException

var settings = new JsonSerializerSettings
{
    TypeNameHandling = TypeNameHandling.None,
    PreserveReferencesHandling = PreserveReferencesHandling.None,
    ReferenceLoopHandling = ReferenceLoopHandling.Ignore
};

在反编译Class1后,我发现Class1的很多属性都标有[ScriptIgnore]属性,这是[JsonIgnore]的类似物,被System.Web.Script.Serialization.JavaScriptSerializer使用,但我需要使用Newtonsoft序列化器。

Class1 是第三方类而言,我无法将[JsonIgnore] 属性添加到所需的属性中。 我知道我可以开发自己的IContractResolver 实现,并在那里处理有问题的属性,但我想避免这个选项。 也许有一种方法可以配置 Newtonsoft 序列化程序以考虑[ScriptIgnore] 属性以及[JsonIgnore]。并像使用ReferenceLoopHandling 一样进行此配置?

如有任何想法,我将不胜感激。

【问题讨论】:

  • 这个没有配置选项。如果你search on githubScriptIgnoreAttribute 甚至不会出现在 Json.NET 源代码树中。 custom contract resolver 是要走的路。我应该回答吗?
  • 另外,你能解释一下为什么你不想实现自定义合约解析器吗?其实很简单。
  • 要使 Json.Net 尊重 [ScriptIgnore][JsonIgnore] 相同,可以使用 @dbc 所说的自定义合约解析器轻松完成。它只是几行代码。如果您立即拒绝该解决方案,那么我能想到的唯一其他选择是分叉和修改 Json.Net 源代码以添加对该属性的支持,或将您的 Class1 映射到代理 DTO 类(或构建从中创建一个 JObject)并对其进行序列化。
  • 您也可以尝试将PreserveReferencesHandling 设置为Objects;这应该可以摆脱StackOverflowException 的问题,但它会大大改变 JSON 输出。有关详细信息,请参阅What is the difference between PreserveReferencesHandling and ReferenceLoopHandling in Json.Net?
  • @BrianRogers,谢谢,我尝试将Objects 用作PreserveReferencesHandling,但不幸的是没有结果,我的问题仍然重现。

标签: json.net


【解决方案1】:

对此没有配置选项。如果你search on githubScriptIgnoreAttribute 甚至不会出现在 Json.NET 源代码树中。

即使您不想实现自己的IContractResolver,这也将是直接的解决方案并且非常简单。首先,定义DefaultContractResolver的如下子类如下:

public class ScriptIgnoreContractResolver : DefaultContractResolver
{
    protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization)
    {
        var property = base.CreateProperty(member, memberSerialization);
        if (!property.Ignored)
        {
            if (property.AttributeProvider.GetAttributes(true).Any(p => p.GetType().FullName == "System.Web.Script.Serialization.ScriptIgnoreAttribute"))
            {
                property.Ignored = true;
            }
        }
        return property;
    }
}

然后序列化如下:

// Define a static member
static readonly IContractResolver myResolver = new ScriptIgnoreContractResolver();

// And use it in your serialization method
var settings = new JsonSerializerSettings
{
    ContractResolver = myResolver,
};
var json = JsonConvert.SerializeObject(rootObject, settings);

您可能想cache the contract resolver for best performance

【讨论】:

  • 我的选项更紧凑一点:public class ScriptIgnoreCompatibleContractResolver : DefaultContractResolver { protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization) { var property = base.CreateProperty(member, memberSerialization); property.Ignored = member.GetCustomAttribute<ScriptIgnoreAttribute>() != null; return property; } } 也许在答案中使用它?抱歉格式化,我无法正确格式化回复中的代码。
  • @AlexanderLysenko - 我想我想避免需要添加对System.Web.Extensions.dll 的引用,这就是我检查类型名称的原因。但是,如果由于其他原因被忽略,您的方式可以将 Ignoredtrue 重置为 false。这就是你想要的吗?
  • 好的,现在我看到我的选择有它的缺点,所以忘记我的评论吧 :)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-06-18
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多