【问题标题】:How to get a value by key from inside a nested JSON Array?如何从嵌套的 JSON 数组中按键获取值?
【发布时间】:2020-08-10 19:45:08
【问题描述】:

使用如下所示的 JSON 结果。我正在尝试从“ActionId”中获取值,在这种情况下为“b0160455-e9d5-4692-850e-4958c8c45f8c”

渲染到 Razor 页面列表视图时,我需要在 foreach 循环中访问此值。

到目前为止,我已经能够访问第一级对象:

例子:

@foreach (var item in Model.LogEvents.EventEntities)
{
      @Html.DisplayFor(modelItem => item.Level)
}

但我无法计算出从这个 JSON 结果中的嵌套数组“属性”中获取值所需的代码:

  {
  "lastReadEventId": "event-58cc86503c8d08d8313d010000000000",
  "scannedEventCount": 1,
  "eventEntities": [
    {
      "timestamp": "2020-08-09T18:55:05.0779216+01:00",
      "properties": [
        {
          "name": "SourceContext",
          "value": "WebApp_RAZOR.Pages.Logs.IndexModel"
        },
        {
          "name": "ActionId",
          "value": "b0160455-e9d5-4692-850e-4958c8c45f8c"
        },
        {
          "name": "ActionName",
          "value": "/Logs/Index"
        },
        {
          "name": "RequestId",
          "value": "0HM1SHK90IVGB:00000001"
        },
        {
          "name": "RequestPath",
          "value": "/Logs/Index"
        },
        {
          "name": "SpanId",
          "value": "|e7eeae4d-4d24315c2124a72d."
        },
        {
          "name": "TraceId",
          "value": "e7eeae4d-4d24315c2124a72d"
        },
        {
          "name": "ParentId",
          "value": ""
        },
        {
          "name": "MachineName",
          "value": "DESKTOP-OS52032"
        },
        {
          "name": "ProcessId",
          "value": 22676
        },
        {
          "name": "ThreadId",
          "value": 14
        }
      ],
      "messageTemplateTokens": [
        {
          "text": "superadmin@hjbuybub.onmicrosoft.com requested the Index page"
        }
      ],
      "eventType": "$DA057814",
      "level": "Information",
      "renderedMessage": "superadmin@gegerggere.onmicrosoft.com requested the Index page",
      "id": "event-5345465467567b575675",
      "links": {
        "Self": "api/events/event-55b5456yubu5u67ub7u5{?download,render,clef}",
        "Group": "api/events/resources"
      }
    }
  ]
}

从 json 结果派生的类:

    public class LogEvents
    {
        public string LastReadEventId { get; set; }
        public int ScannedEventCount { get; set; }
        public EventEntity[] EventEntities { get; set; }
    }

    public class EventEntity
    {
        public DateTime Timestamp { get; set; }
        public Property[] Properties { get; set; }
        public MessageTemplateToken[] MessageTemplateTokens { get; set; }
        public string EventType { get; set; }
        public string Level { get; set; }
        public string RenderedMessage { get; set; }
        public string Id { get; set; }
        public Links Links { get; set; }
    }

    public class Links
    {
        public string Self { get; set; }
        public string Group { get; set; }
    }

    public class Property
    {
        public string Name { get; set; }
        public object Value { get; set; }
    }

    public class MessageTemplateToken
    {
        public string Text { get; set; }
    } 

我在这里尝试过其他问答,但每个人的要求总是不同的并且卡住了。

【问题讨论】:

  • 你是否做过“将 json 粘贴为类”/使用 QuickType.io 从 json 生成类?
  • 我确实使用编辑将 json 结果粘贴到类中,然后在 Visual Studio 中粘贴特殊。如果这有帮助,只需将它们添加到我的 Q...

标签: c# arrays json


【解决方案1】:

其中一个选项是使用 Newtonsoft 的 Json.NET json path implementation

var actionIds = JObject.Parse(json)
    .SelectTokens("$.eventEntities[*].properties[?(@.name == 'ActionId')].value")
    .Select(p => p.ToString())
    .ToList();

或者你的类结构应该是:

var actionIds = Model.LogEvents
    .SelectMany(le => le.Properties)
    .Where(p => p.Name == "ActionId")
    .Select(p => p.Value) // also can add `ToString` here since Value is an object
    .ToList();

【讨论】:

  • 在遍历 Razor 列表视图的循环时如何工作?即我为第一级对象提供的示例是@Html.DisplayFor(modelItem => item.Level)
  • @OJB1 您正在寻找类似thisthis 的东西?
  • json 路径实现看起来与我所追求的一致,之前没见过,所以在我们说话的时候阅读它。
  • 无法弄清楚...使用 Newtonsoft 的 Json.NET json 路径实现:我尝试了 '@Html.DisplayFor(modelItem => item.Properties[?(@.name == 'ActionId') ].value])' 但它甚至不会编译
【解决方案2】:

尝试使用CHOETL json阅读器(from nuggets)。您需要从那里加载 JSON 并读取 JSON 并使用动态“foreach 项”。如果 item.name == "ActionId",那么对 item.value 做任何你想做的事情。

这是指南:https://github.com/Cinchoo/ChoETL

【讨论】:

    【解决方案3】:

    像这样:

    @foreach (var item in Model.LogEvents.EventEntities)
    {
          @Html.DisplayFor(modelItem => item.Level.Properties
            .Single(x => x.Name == "ActionId").Value)
    }
    

    意思是“在item.Properties数组中,获取x.Name等于"ActionId"的唯一元素x并返回它的.Value

    如果你不希望它在没有这样的元素时崩溃,你可以看看:

    @Html.DisplayFor(modelItem => 
      (
        item.Level.Properties
          .SingleOrDefault(x => x.Name == "ActionId") 
          ?? new Property(){ Value = "Not found" }
      ).Value
    

    Single[OrDefault] 坚持只匹配规则的一个元素。如果您不希望它在有多个名称为 ActionId 的元素时崩溃,请使用[First/Last][OrDefault]。如果您想要一个既不是第一个也不是最后一个的 ActionId,您必须通过任何逻辑来挖掘它以找到您需要的它们(即“第二个”、“值以 'a' 开头的那个”等)


    真的,您甚至不应该在您的视图中执行所有这些代码。准备模型并将其发送到视图的整个想法是模型已准备好使用简单的属性和数据,为视图格式化和准备。在你看来,你不应该做大量复杂的 LINQ、错误处理、moel 转换等。

    “仅仅因为你可以,并不意味着你应该”:)

    【讨论】:

    • 感谢 Caius,我尝试了您的上述代码,并接受您的 cmets 关于不在视图中执行此级别查询的意见。无论如何都不会为我编译“表达式树 lambda 可能不包含空传播运算符”消息。您是否建议我应该先将 json 返回的数据添加到页面模型中的列表中,然后再将其带到视图中?
    • 我修复了代码,所以它不使用空属性,但是是的;这正是我要说的。模型应该准备好其中的数据;它不应该是您的模型包含这个可能/不存在/使用的非常复杂的对象树,让您的视图通过它们进行挑选并采取相应的行动。生成模型的代码应该完成大部分的展平和验证。这并不是说模型不应该有分层的元素,只是模型应该代表视图需要完成的工作,而不是挥霍每个不相关的数据项
    猜你喜欢
    • 1970-01-01
    • 2016-08-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-12-19
    • 1970-01-01
    • 2020-11-06
    相关资源
    最近更新 更多