子属性的 JSON .NET 自定义名称解析器

2023-12-05

我有一个 API,它从 MongoDB 返回一个 JSON 对象,其中属性之一是“开放式”文档,这意味着它可以是any该属性的有效 JSON。我事先不知道属性的名称是什么,它们可以是任何字符串。我只知道这个特定的属性需要序列化exactly它如何存储在数据库中。因此,如果最初存储的属性名称是“Someproperty”,则 JSON 中的序列化响应需要是“Someproperty”,而不是“someProperty”。

我们有这样的配置:

ContractResolver = new CamelCasePropertyNamesContractResolver();

在我们的 CustomJsonSerializer 中,但在返回“开放式”JSON 时,它会扰乱响应的格式。它对所有这些属性进行驼峰式封装,而实际上我们希望响应与它们在 MongoDB (BSON) 中的存储方式完全相同。我知道这些值在通过数据库存储/检索时保持其大小写,所以这不是问题。

我如何告诉 JSON.net 从本质上绕过特定数据点的所有子属性的 CamelCasePropertyNameResolver?

编辑: 只是为了提供更多信息,并分享我已经尝试过的内容:

我考虑过像这样重写 PropertyNameResolver:

protected override string ResolvePropertyName(string propertyName)
{
      if (propertyName.ToLower().Equals("somedocument"))
      {
                return propertyName;
      }
      else return base.ResolvePropertyName(propertyName);
}

但是,如果我有这样的 JSON 结构:

{
   "Name" : "MyObject",
   "DateCreated" : "11/14/2016",
   "SomeDocument" : 
   {
      "MyFirstProperty" : "foo",
      "mysecondPROPERTY" : "bar",
      "another_random_subdoc" : 
      {
         "evenmoredata" : "morestuff"
      }
   }
}

那么我需要所有属性(任何子属性的名称)保持原样。我发布的上述覆盖(我相信)只会忽略与“somedocument”的精确匹配,并且仍然会驼峰式命名所有子属性。


您可以做的是,对于有问题的属性,创建一个custom JsonConverter使用不同的方法序列化有问题的属性值JsonSerializer使用不同的合约解析器创建,如下所示:

public class AlternateContractResolverConverter : JsonConverter
{
    [ThreadStatic]
    static Stack<Type> contractResolverTypeStack;

    static Stack<Type> ContractResolverTypeStack { get { return contractResolverTypeStack = (contractResolverTypeStack ?? new Stack<Type>()); } }

    readonly IContractResolver resolver;

    JsonSerializerSettings ExtractAndOverrideSettings(JsonSerializer serializer)
    {
        var settings = serializer.ExtractSettings();
        settings.ContractResolver = resolver;
        settings.CheckAdditionalContent = false;
        if (settings.PreserveReferencesHandling != PreserveReferencesHandling.None)
        {
            // Log an error throw an exception?
            Debug.WriteLine(string.Format("PreserveReferencesHandling.{0} not supported", serializer.PreserveReferencesHandling));
        }
        return settings;
    }

    public AlternateContractResolverConverter(Type resolverType)
    {
        if (resolverType == null)
            throw new ArgumentNullException("resolverType");
        resolver = (IContractResolver)Activator.CreateInstance(resolverType);
        if (resolver == null)
            throw new ArgumentNullException(string.Format("Resolver type {0} not found", resolverType));
    }

    public override bool CanRead { get { return ContractResolverTypeStack.Count == 0 || ContractResolverTypeStack.Peek() != resolver.GetType(); } }
    public override bool CanWrite { get { return ContractResolverTypeStack.Count == 0 || ContractResolverTypeStack.Peek() != resolver.GetType(); } }

    public override bool CanConvert(Type objectType)
    {
        throw new NotImplementedException("This contract resolver is intended to be applied directly with [JsonConverter(typeof(AlternateContractResolverConverter), typeof(SomeContractResolver))] or [JsonProperty(ItemConverterType = typeof(AlternateContractResolverConverter), ItemConverterParameters = ...)]");
    }

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        using (ContractResolverTypeStack.PushUsing(resolver.GetType()))
            return JsonSerializer.CreateDefault(ExtractAndOverrideSettings(serializer)).Deserialize(reader, objectType);
    }

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        using (ContractResolverTypeStack.PushUsing(resolver.GetType()))
            JsonSerializer.CreateDefault(ExtractAndOverrideSettings(serializer)).Serialize(writer, value);
    }
}

internal static class JsonSerializerExtensions
{
    public static JsonSerializerSettings ExtractSettings(this JsonSerializer serializer)
    {
        // There is no built-in API to extract the settings from a JsonSerializer back into JsonSerializerSettings,
        // so we have to fake it here.
        if (serializer == null)
            throw new ArgumentNullException("serializer");
        var settings = new JsonSerializerSettings
        {
            CheckAdditionalContent = serializer.CheckAdditionalContent,
            ConstructorHandling = serializer.ConstructorHandling,
            ContractResolver = serializer.ContractResolver,
            Converters = serializer.Converters,
            Context = serializer.Context,
            Culture = serializer.Culture,
            DateFormatHandling = serializer.DateFormatHandling,
            DateFormatString = serializer.DateFormatString,
            DateParseHandling = serializer.DateParseHandling,
            DateTimeZoneHandling = serializer.DateTimeZoneHandling,
            DefaultValueHandling = serializer.DefaultValueHandling,
            EqualityComparer = serializer.EqualityComparer,
            // No Get access to the error event, so it cannot be copied.
            // Error = += serializer.Error
            FloatFormatHandling = serializer.FloatFormatHandling,
            FloatParseHandling = serializer.FloatParseHandling,
            Formatting = serializer.Formatting,
            MaxDepth = serializer.MaxDepth,
            MetadataPropertyHandling = serializer.MetadataPropertyHandling,
            MissingMemberHandling = serializer.MissingMemberHandling,
            NullValueHandling = serializer.NullValueHandling,
            ObjectCreationHandling = serializer.ObjectCreationHandling,
            ReferenceLoopHandling = serializer.ReferenceLoopHandling,
            // Copying the reference resolver doesn't work in the default case, since the
            // actual BidirectionalDictionary<string, object> mappings are held in the 
            // JsonSerializerInternalBase.
            // See https://github.com/JamesNK/Newtonsoft.Json/blob/master/Src/Newtonsoft.Json/Serialization/DefaultReferenceResolver.cs
            ReferenceResolverProvider = () => serializer.ReferenceResolver,
            PreserveReferencesHandling = serializer.PreserveReferencesHandling,
            StringEscapeHandling = serializer.StringEscapeHandling,
            TraceWriter = serializer.TraceWriter,
            TypeNameHandling = serializer.TypeNameHandling,
            // Changes in Json.NET 10.0.1
            //TypeNameAssemblyFormat was obsoleted and replaced with TypeNameAssemblyFormatHandling in Json.NET 10.0.1
            //TypeNameAssemblyFormat = serializer.TypeNameAssemblyFormat,
            TypeNameAssemblyFormatHandling = serializer.TypeNameAssemblyFormatHandling,
            //Binder was obsoleted and replaced with SerializationBinder in Json.NET 10.0.1
            //Binder = serializer.Binder,
            SerializationBinder = serializer.SerializationBinder,
        };
        return settings;
    }
}

public static class StackExtensions
{
    public struct PushValue<T> : IDisposable
    {
        readonly Stack<T> stack;

        public PushValue(T value, Stack<T> stack)
        {
            this.stack = stack;
            stack.Push(value);
        }

        // By using a disposable struct we avoid the overhead of allocating and freeing an instance of a finalizable class.
        public void Dispose()
        {
            if (stack != null)
                stack.Pop();
        }
    }

    public static PushValue<T> PushUsing<T>(this Stack<T> stack, T value)
    {
        if (stack == null)
            throw new ArgumentNullException();
        return new PushValue<T>(value, stack);
    }
}

然后像这样使用它:

public class RootObject
{
    public string Name { get; set; }
    public DateTime DateCreated { get; set; }

    [JsonProperty(NamingStrategyType = typeof(DefaultNamingStrategy))]
    [JsonConverter(typeof(AlternateContractResolverConverter), typeof(DefaultContractResolver))]
    public SomeDocument SomeDocument { get; set; }
}

public class SomeDocument
{
    public string MyFirstProperty { get; set; }
    public string mysecondPROPERTY { get; set; }
    public AnotherRandomSubdoc another_random_subdoc { get; set; }
}

public class AnotherRandomSubdoc
{
    public string evenmoredata { get; set; }
    public DateTime DateCreated { get; set; }
}

(这里我假设你想要"SomeDocument"属性名称要逐字序列化,即使您的问题并不完全清楚。为此,我正在使用JsonPropertyAttribute.NamingStrategyType来自 Json.NET 9.0.1。如果您使用的是早期版本,则需要显式设置属性名称。)

那么生成的 JSON 将是:

{
  "name": "Question 40597532",
  "dateCreated": "2016-11-14T05:00:00Z",
  "SomeDocument": {
    "MyFirstProperty": "my first property",
    "mysecondPROPERTY": "my second property",
    "another_random_subdoc": {
      "evenmoredata": "even more data",
      "DateCreated": "2016-11-14T05:00:00Z"
    }
  }
}

请注意,此解决方案不适用于保留对象引用。如果您需要它们一起工作,您可能需要考虑一种基于堆栈的方法,类似于Json.NET 按深度和属性序列化

演示小提琴here.

顺便说一句,您是否考虑过将此 JSON 存储为原始字符串文字,如答案所示这个问题?

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

子属性的 JSON .NET 自定义名称解析器 的相关文章

  • 在 TPL Dataflow 中,是否可以在创建块之后但使用之前更改 DataflowBlockOptions?

    有效果吗 我想推迟设置 ExecutionDataflowBlockOptions SingleProducerConstrained 属性 直到我准备好将网络链接在一起 因为 我想将创建块及其语义与将网络及其语义链接在一起分开 但据我所知
  • 忽略父进程中的信号

    我正在尝试实现一个 shell 程序 我希望 shell 程序忽略 SIG INT ctrl c 但在我的程序中 子进程也会忽略 SIG INT 信号 但它不应该这样做 因为 exec 应该将子进程带到另一个程序 并且该程序默认情况下应该处
  • 使用 R.Net 版本 1.5.5 创建 REngine 实例

    我正在尝试创建一个 Hello World 示例R Language using R Net版本1 5 5 从 NuGet 加载 不幸的是 我见过的在线示例都不起作用 这就是我所做的 已安装Microsoft R Open 3 2 4 增强
  • 合并多边形的高效算法

    我有一个多边形列表 在这个列表中 一些多边形重叠 或者接触其他多边形 我的任务是合并所有相互重叠或接触的多边形 我有一个union执行此操作的方法 做到这一点最有效的方法是什么 我目前能想到的是循环遍历多边形列表 检查合并列表以查看该多边形
  • 有没有办法使用 ews c# 确定电子邮件是否是回复/响应?

    我正在编写一个支持系统 这是我第一次使用 EWS 到目前为止 我已经相当成功了 我可以提取我需要的信息 发送电子邮件 一切正常 我确实有点头疼 有没有办法判断电子邮件是否实际上是回复 该应用程序的基本思想是有人发送电子邮件 我们回复并给他们
  • Image.FromStream() 方法返回 Invalid Argument 异常

    我正在从智能相机成像器捕获图像 并通过套接字编程从相机接收字节数组 NET 应用程序是客户端 相机是服务器 问题是我在运行时收到 System InvalidArgument 异常 private Image byteArrayToImag
  • 使用 C# 启动 Outlook

    我可以让 C 在代码中启动 Outlook 吗 在 VB6 中 我们使用对象 Outlook Application 并编写 Set oOutlook CreateObject Outlook Application Set oNameSp
  • FxCop 和 GAC 疯狂

    当我尝试分析依赖于模式和实践 企业库数据 以及其他 2 0 0 0 的项目时使用 FxCop FxCop 抱怨它不能 定位程序集引用 即使正在分析的应用程序 dll 是根据其编译的此版本及其在 GAC 中 如果我浏览到 GAC 尝试选择相同
  • Makefile:如何正确包含头文件及其目录?

    我有以下 makefile CC g INC DIR StdCUtil CFLAGS c Wall I INC DIR DEPS split h all Lock o DBC o Trace o o cpp DEPS CC o lt CFL
  • 安全移动 C++ 对象

    我听到过一些警告 不要通过以下方式将对象运送到另一个内存位置memcpy 但不知道具体原因 除非它包含的成员做了依赖于内存位置的棘手事情 否则这应该是完全安全的 或者不是 编辑 预期的用例是像这样的数据结构vector 它存储对象 不是po
  • autofac 中的条件组件注册

    是否可以根据其他组件的状态有条件地注册组件 就像是 ContainerBuilder RegisterConditionally
  • 调用 Console.ReadLine() 的方法的 C# 单元测试

    我想为名为的类的成员函数创建一个单元测试ScoreBoard它存储了一场比赛中排名前五的球员 问题是我为 SignInScoreBoard 正在呼叫Console ReadLine 这样用户就可以输入他们的名字 public void Si
  • 从 ASP.NET Web API 返回 HTML

    如何从 ASP NET MVC Web API 控制器返回 HTML 我尝试了下面的代码 但由于未定义 Response Write 而出现编译错误 public class MyController ApiController HttpP
  • 在 Windows 上构建 MLT 框架时出错

    我一直在遵循官方提供的构建指南here http www mltframework org bin view MLT WindowsBuild 我需要 MLT 来创建视频播放器 并且我选择仅安装前 4 个库 如指南中所述 FFmpeg SD
  • 如何使用 C# 以编程方式识别对方法的引用数量

    我最近继承了需要一些修剪和清理的 C 控制台应用程序 长话短说 该应用程序由一个包含超过 110 000 行代码的类组成 是的 单个类中有超过 110 000 行 当然 该应用程序是我们业务的核心 全天候运行更新动态网站上使用的数据 尽管我
  • GCC编译非常慢(文件大)

    我正在尝试编译一个大的 C 文件 专门用于 MATLAB mexing C 文件大约 20 MB 可用来自 GCC 错误跟踪器 https gcc gnu org bugzilla attachment cgi id 36632如果你想玩一
  • MacOS 每秒唤醒次数错误

    构建 Rails 应用程序 ruby 2 4 0p0 Rails 5 1 4 并使用我的 Macbook Air MacOS High Sierra 10 13 2 进行本地测试 我不断遇到此问题 过去 241 秒内有 45001 次唤醒
  • 删除指针后将其设为 NULL 是一个好习惯吗?

    我首先要说的是 使用智能指针 您将永远不必担心这个问题 下面的代码有什么问题 Foo p new Foo use p delete p p NULL 这是由答案和评论 https stackoverflow com questions 19
  • 从 C# 应用程序调用 ASP.net Web 服务

    我有个问题 我如何调用 Web 服务并从 C 桌面应用程序获取结果 我正在制作一个桌面应用程序 我希望它能够连接到我的在线 ASP net Web 服务 这怎么可能 在 解决方案资源管理器 中 右键单击项目节点并选择 添加 Service参
  • System.IO.IOException:进程无法访问文件“.txt”,因为它正在被另一个进程使用

    我正在使用下一个代码来记录 Web 应用程序的错误 using StreamWriter myStream new StreamWriter sLogFilePath true myStream WriteLine string Forma

随机推荐

  • PDF 中的透明图像

    This PDF由多个源代码片段组成 其中五个是包含 Alpha 通道的 PNG 一种是没有 Alpha 通道的 PNG 最后一张是带有透明效果的 Photoshop PDF 这些部件是使用 ABCpdf 9 1 组装的 在 Acrobat
  • 在 CLX TEdit 的 KeyPress 事件中拦截 TAB 键

    我有一个 TEdit VisualCLX 组件 我想覆盖 onKeyPress 事件中 TAB 键的行为 但是如果我尝试拦截 KeyPress 事件中的 TAB 键 它将不起作用 因为当在 TEdit 上按下 Tab 键 如何拦截 TEdi
  • 无法在 centos VPS 上通过 google smtp 发送电子邮件

    我正在尝试通过 google SMTP 发送电子邮件 该代码在我本地 Windows PC 的 tomcat 中运行良好 但我在我的 centos VPS 上遇到了这个错误 org apache commons mail EmailExce
  • 当我删除指针时出现分段错误(核心转储)

    我正在尝试从链接列表中删除重复项 并遇到了一个问题 这可能是显而易见且简单的 但我没有使用过C 多年来 我无法通过阅读类似的问题来找出我做错了什么 下面是我的代码的一部分 我删除了不相关的部分 例如构造函数 其他方法等 template
  • asp.net webapi 2 post参数始终为空

    过去一个小时我一直在试图弄清楚这是我们的 但我不明白它出了什么问题 这篇文章来自我正在编写的 Xamarin 应用程序 使用 RestSharp 便携式客户端 POST http 192 168 30 103 8080 api Order
  • 类型错误:不可散列的类型:'dict',当 dict 用作​​另一个 dict 的键时 [重复]

    这个问题在这里已经有答案了 我有这段代码 for element in json referenceElement keys 当我运行该代码时 我收到此错误 类型错误 不可散列的类型 dict 该错误的原因是什么 我可以采取什么措施来修复它
  • CountIf - 如何转义特殊字符(尖括号)

    我正在尝试使用 VBA 计算 Excel 电子表格中特定单元格值出现的次数 单元格值是一个 XML 标记 函数将尖括号解释为小于 大于 如何逃脱这些字符 微软说 您可以使用通配符 问号 和星号 作为条件 问号匹配任何单个字符 星号匹配任何字
  • ui-router 默认子状态不起作用

    我正在测试UI Router嵌套状态 但我无法在父 子场景中设置默认状态 请帮助 图书馆 角度 1 3 15 用户界面路由器 0 2 15 导航路径 home settings parent state page settings defa
  • 如何在约束布局上实现重叠/负边距?

    是否可以在约束布局上实现负边距以实现重叠 我试图让图像以布局为中心 并有一个文本视图 使其与 x dp 重叠 我尝试设置负保证金值 但没有成功 如果有办法实现这一点那就太好了 Update 约束布局现在版本 2 1 0 alpha2 支持负
  • 从一个函数返回不同维度的数组;在 F# 中可以吗?

    我正在尝试将一些 Python 转换为 F 特别是numpy random randn 该函数采用可变数量的 int 参数 并根据参数的数量返回不同维度的数组 我相信这是不可能的 因为不能有一个返回不同类型的函数 int int int 等
  • 使用代码更新故事板约束

    我有一个UIImage在代码中 我想在按下按钮时垂直放大 这UIImage完全限制在故事板中 我想在按下按钮时更改其高度 我已经链接了UIImage及其在代码中的高度约束 IBOutlet weak var botBotCons NSLay
  • 当我不将 .Save() 的位图 .Dispose() 保存到 MemoryStream 时,为什么会出现内存泄漏?

    假设我创建了一个位图 Bitmap bitmap new Bitmap 320 200 当我将其写入某个流时 在我的例子中 它是一个 HttpResponseStream 由 HttpListenerResponse 给出 一切都很好 bi
  • Java机器人类mouseMove不去指定的位置

    老实说 我不完全确定出了什么问题 这是 if 和 if else 下的大量其他基本机器人命令动作的简短版本 每当我运行该程序时 鼠标应移动到指定位置并单击 但是 当我运行程序时 它不会移动到我指示的位置 而是每次运行时它都会移动到不同的位置
  • 将大型 Git 存储库拆分为许多较小的存储库

    成功将 SVN 存储库转换为 Git 后 我 现在拥有一个非常大的 Git 存储库 我想将其分解为多个较小的存储库并维护历史记录 那么 有人可以帮助分解可能如下所示的存储库 MyHugeRepo git DIR A DIR B DIR 1
  • 如何在wpf中实现主题化

    我想在 WPF 中实现 ASP Net 类型主题 用户可以选择各种预定义主题 并且可以切换到另一个主题 为了实现这一点 我尝试为每个主题创建不同的资源字典 并使用键存储所需的样式 所有主题中的键集合都是相同的 但每个主题的定义都不同 我使用
  • 将矩阵中每个等于 0 的元素替换为上一行的相应元素

    我正在使用 R 我有一个矩阵 我想用上面行的相应元素替换它等于零的每个元素 例如 我创建了以下矩阵 AA lt matrix c 1 2 3 1 4 5 1 0 2 ncol 3 nrow 3 1 2 3 1 1 1 1 2 2 4 0 3
  • 如何在两个 Android 应用之间共享应用内购买

    我有两个 Android 应用程序 app1 和 app2 它们都是免费的 但 app2 包含应用程序内购买升级 现在我要将这两个应用程序合并到 app1 没有应用内购买的应用程序 中 我的问题是 如何保留已在 app2 中消费的购买 以便
  • 使用 set_xlim() 切片图后 matplotlib autoscale(axis='y')

    作为演示 我绘制了 x 0 到 x 9 其中 x 值的范围为 10 到 20 然后我对这些图像进行切片 得到 9 个切片 x 10 到 11 11 到 12 等等到 18 到 19 我希望裁剪图像 以便 y 值始终在每个切片中从上到下分布
  • CSS3 可以添加文本渐变吗?

    我正在寻找在文本中添加渐变 网络图们有一个快速提示关于那个 但它仅适用于 webkit 浏览器 由于这是相当老的帖子 我正在检查是否有任何跨浏览器解决方案 忽略 ie 我知道如何使用背景渐变图像 我知道在 Firefox 中实现此功能的唯一
  • 子属性的 JSON .NET 自定义名称解析器

    我有一个 API 它从 MongoDB 返回一个 JSON 对象 其中属性之一是 开放式 文档 这意味着它可以是any该属性的有效 JSON 我事先不知道属性的名称是什么 它们可以是任何字符串 我只知道这个特定的属性需要序列化exactly