Reputation: 2785
Using the JSON result shown below. I'm trying to get the value from the "ActionId" which in this case is "b0160455-e9d5-4692-850e-4958c8c45f8c"
I need to access this value in a foreach loop when rendering to a Razor Page list view.
So far I've been able to access the first level objects:
Example:
@foreach (var item in Model.LogEvents.EventEntities)
{
@Html.DisplayFor(modelItem => item.Level)
}
But I just cant work out the required code to get the values from the nested array 'Properties' inside this JSON result:
{
"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": "[email protected] requested the Index page"
}
],
"eventType": "$DA057814",
"level": "Information",
"renderedMessage": "[email protected] requested the Index page",
"id": "event-5345465467567b575675",
"links": {
"Self": "api/events/event-55b5456yubu5u67ub7u5{?download,render,clef}",
"Group": "api/events/resources"
}
}
]
}
Classes derived from json result:
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; }
}
I've tried following other Q&A here, but everyone's requirements are always different and getting stuck.
Upvotes: 0
Views: 1913
Reputation: 65
Try using CHOETL json reader(from nuggets). What you need from there is load the JSON and read the JSON and use a dynamic "foreach item". If item.name == "ActionId", then do whatever you want with item.value.
Here's is the guide: https://github.com/Cinchoo/ChoETL
Upvotes: 1
Reputation: 74605
Like this:
@foreach (var item in Model.LogEvents.EventEntities)
{
@Html.DisplayFor(modelItem => item.Level.Properties
.Single(x => x.Name == "ActionId").Value)
}
It means "within the item.Properties
array, get the only element x where x.Name
equals "ActionId"
and return its .Value
If you don't want it to crash when there is no such element, you could look at:
@Html.DisplayFor(modelItem =>
(
item.Level.Properties
.SingleOrDefault(x => x.Name == "ActionId")
?? new Property(){ Value = "Not found" }
).Value
Single[OrDefault] insists on only one element matching the rule. If you don't want it to crash when there are multiple elements with a name of ActionId, use [First/Last][OrDefault]
. If you want an ActionId that is neither first or last, you'll have to dig it out by whatever logic for finding them you demand (i.e. "the second one", "the one whose value starts with an 'a'" etc)
Really you shouldn't even be doing all this code in your view. The whole idea of preparing a model and sending it to the view is that the model is ready to go with simple properties and data, formatted and prepared for the view. You shouldn't be doing massively complicated amounts of LINQ, error handling, moel transformation etc in your view..
"Just because you can, doesn't mean you should" :)
Upvotes: 0
Reputation: 141665
One of the options is to use Newtonsoft's Json.NET json path implementation:
var actionIds = JObject.Parse(json)
.SelectTokens("$.eventEntities[*].properties[?(@.name == 'ActionId')].value")
.Select(p => p.ToString())
.ToList();
Or with your class structure it should be:
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();
Upvotes: 2