I have a JSON that has the following pattern to be created before
hitting the API, See below
"recipientSetInfos":
[
{
"recipientSetMemberInfos":
[
{
"fax": "",
"email": ""
}
],
"recipientSetRole":
{
"SIGNER": "enum",
"APPROVER": "enum"
},
"signingOrder": 0
}
]
Using this predefined Format, i want to create Multiple signer set's,
like the below.
"recipientSetInfos":
[
{
"recipientSetMemberInfos":
[{
"email": "def#gmail.com"
}],
"recipientSetRole": "SIGNER"
}, {
"recipientSetMemberInfos": [{
"email": "abc#gmail.com"
}],
"recipientSetRole": "SIGNER"
}],
I am using C# Programming Language, if i just hard code it & send. It
works but if i want to create dynamically. How can i achieve this.
Currently I am using this like
RecipientSetInfo rec_Info = new RecipientSetInfo();
rec_Info.recipientSetMemberInfos = List_Emails;
rec_Info.recipientSetRole = "SIGNER";
List_Recipients.Add(rec_Info);
which gives an output of :
{
"recipientSetMemberInfos":
[
{"email":"abc#ae.com"},
{"email":"def#gmail.com"},
{"email":"fgh#gmail.com"}
],
"recipientSetRole":"SIGNER"
}
But using this logic, i am not getting the desired output. It is
considering all 3 emails as one.
Just to add, one more thing with the help of one user, i tried to code out this
foreach (var email in List_Emails)
{
var rec_Info = new RecipientSetInfo();
rec_Info.recipientSetRole = "SIGNER";
List_Recipients.Add(rec_Info);
}
But problem still exists, since "recipientSetInfos" has two subdivisions i.e. recipientSetRole & recipientSetMemberInfos within which "recipientSetMemberInfos" has one attribute Email.
So when i add the two lists together it comes out Email to be Null
"recipientSetInfos":
[
{"recipientSetMemberInfos":null,
"recipientSetRole":"SIGNER"
},
{"recipientSetMemberInfos":null,
"recipientSetRole":"SIGNER"
}
]
Structure for both the elements i have created like -
public class RecipientSetMemberInfo
{
public string email { get; set; }
}
public class RecipientSetInfo
{
public List<RecipientSetMemberInfo> recipientSetMemberInfos { get; set; }
public string recipientSetRole { get; set; }
}
Please suggest ??
Your problem is that you create one RecipientSetInfo instead of one for each email.
The following will loop through List_Emails collection and will add them to the list List_Recipients.
foreach (var email in List_Emails)
{
var rec_Info = new RecipientSetInfo();
rec_Info.recipientSetRole = "SIGNER";
List_Recipients.Add(rec_Info);
}
Related
I have a JSON string that I receive from a service call that has the following format:
{
"DataKEY": [
{
"value": {
"timestamp": "2022-10-26T05:00:00Z",
"value": 0.0
}
},
{
"value": {
"timestamp": "2022-10-26T06:00:00Z",
"value": 0.0
}
}
]
}
How can I change just the node names of the middle "value" to obtain the following output to send to another service:
{
"DataKEY": [
{
"KEY": {
"timestamp": "2022-10-26T05:00:00Z",
"value": 0.0
}
},
{
"KEY": {
"timestamp": "2022-10-26T06:00:00Z",
"value": 0.0
}
}
]
}
I need to change the first level of nodes with the name "value" to a given "KEY" in the response string, I tried using string.Replace("value", "KEY") but that replaces the inner level as well.
How can I change only the first level of nodes?
When the string represents a JSON data response then you will find it easier to manipulate the names of the properties or the structure of the object graph by first deserializing the data transforming the data to the desired output, then serialising the transformed object back into a string.
If we only need to change the names of some elements, you could use a JSON reader and writer process to step through the file or we can take advantage of some serialization tricks to avoid the transformation step.
We can configure the serialization provider to omit null valued properties which means we can provide 2 properties on a class definition that will be mapped to the same internal backing field, in the example below I have mapped a second property to the inner Key value, this only has a setter making it write-only. This way any deserialization process can write to it via Key or Value named property, but in the serialization process the Value property will always return null and can be omitted from the output:
this is the important aspect and probably the only scenario I've ever used a write-only property:
public DataKeyValue Key { get;set; }
public DataKeyValue Value
{
get
{
return null;
}
set
{
Key = value;
}
}
This is the full class definition:
public class DataKeyWrapper
{
public DataKey[] DataKEY { get;set; }
}
public class DataKey
{
public DataKeyValue Key { get;set; }
public DataKeyValue Value
{
get
{
return null;
}
set
{
Key = value;
}
}
}
public class DataKeyValue
{
public DateTime timestamp { get;set; }
public Decimal value { get;set; }
}
The you can deserialize and re-serialize with this logic:
using Newtonsoft.Json;
...
var input = JsonConvert.DeserializeObject<DataKeyWrapper>(input);
var output = JsonConvert.SerializeObject(input, new JsonSerializerSettings
{
Formatting = Newtonsoft.Json.Formatting.Indented,
NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore
});
You can view a full fiddle on this here: https://dotnetfiddle.net/YUsRn8
The Response:
{
"DataKEY": [
{
"Key": {
"timestamp": "2022-10-26T05:00:00Z",
"value": 0.0
}
},
{
"Key": {
"timestamp": "2022-10-26T06:00:00Z",
"value": 0.0
}
}
]
}
This time I am needing some help deserializing some data that comes from a Web API using using System.Text.Json. After searching all over the place I had found nothing that can really help me solving this issue
Here is a sample of the data:
For the UF Indicator:
{
"UFs": [
{
"Valor": "30.008,40",
"Fecha": "2021-09-10"
}
]
}
For USD Indicator:
{
"Dolares": [
{
"Valor": "791,28",
"Fecha": "2021-09-10"
}
]
}
For UTM Indicator:
{
"UTMs": [
{
"Valor": "52.631",
"Fecha": "2021-09-01"
}
]
}
And a sample for USD with multiple sets of data:
{
"Dolares": [
{
"Valor": "767,10",
"Fecha": "2021-09-02"
},
{
"Valor": "768,36",
"Fecha": "2021-09-03"
},
{
"Valor": "766,53",
"Fecha": "2021-09-06"
},
{
"Valor": "770,33",
"Fecha": "2021-09-07"
},
{
"Valor": "777,94",
"Fecha": "2021-09-08"
},
{
"Valor": "787,51",
"Fecha": "2021-09-09"
},
{
"Valor": "791,28",
"Fecha": "2021-09-10"
}
]
}
This is the class I need to Deserialize to:
public class Indicador : IIndicador
{
public string Valor { get; set; }
public string Fecha { get; set; }
}
The issue starts when I try to Deserialize using this:
var dataFromApi = await httpResponse.Content.ReadAsStringAsync();
var indicador = JsonSerializer.Deserialize<Indicador>(dataFromApi);
I also tried using this "solution" but with no luck at all:
var dataFromApi = await httpResponse.Content.ReadAsStringAsync();
var indicador = JsonSerializer.Deserialize<Dictionary<string,List<indicador>>>(dataFromApi);
So far the only solution has been to create a "container" class that can help me handle that odd "UFs" as a list, since this WebAPI can return multiple other economics indicators than "UFs" which can change to a lot of other concepts, is there a way to map what ever comes from the WebAPI to my generic Indicador class?, the idea is to use a simple object when there is just 1 data and an IEnumerable when there are more than one. I need to stop the dependency for each type of indicator available.
Concerns / Areas of Improvement
Your final paragraph is a little vague and you don't have anymore examples. As such the answer might not be quite as specific as you are looking for.
multiple other economics indicators than "UFs"
Would be nice to see some other examples.
map what ever comes from the WebAPI to my generic Indicador class
Potentially possible, but it remains to be seen how the other data is structured.
Simplest Example
I think you are missing this part of the deserialization process
List<Indicador> indicadors = dataDict["UFs"]; // <-- Will fail If "UFs" is not present
Below is a top level C# program to how to deserialize the given data to a List<Indicador>.
using System;
using System.Text.Json;
using System.Collections.Generic;
// test data
string dataFromApi = #"{
""UFs"": [
{
""Valor"": ""30.008,40"",
""Fecha"": ""2021-09-10""
},
{
""Valor"": ""40.008,50"",
""Fecha"": ""2021-10-10""
}
]
}";
var dataDict = JsonSerializer.Deserialize<Dictionary<string, List<Indicador>>>(dataFromApi);
List<Indicador> indicadors = dataDict["UFs"]; // <-- Will fail If "UFs" is not present
// print out the indicadors
indicadors.ForEach(indicador => Console.WriteLine(indicador));
// Using records because they are brief and come with a good default ToString() method
// You can use regular class if you require
public abstract record IIndicador(string Valor, string Fecha);
public record Indicador(string Valor, string Fecha): IIndicador(Valor, Fecha);
The output of the above top level C# program
Indicador { Valor = 30.008,40, Fecha = 2021-09-10 }
Indicador { Valor = 40.008,50, Fecha = 2021-10-10 }
If "UFs" key is not guaranteed then you can use one of the Dictionary methods to determine if the key is present. For example
if (dataDict.ContainsKey("UFs")) ...
Speculation
Going out on a limb here trying to address some of the aspects of your last paragraph. (You will need to clarify if this address all your concerns and adapt to meet your needs) System.Text.Json also has JsonConverterFactory and JsonConverter<T> for more advanced Conversion requirements should you need them.
using System;
using System.Linq;
using System.Text.Json;
using System.Collections.Generic;
// test data
string multiDataFromApi = #"{
""UFs"": [
{
""Valor"": ""30.008,40"",
""Fecha"": ""2021-09-10""
},
{
""Valor"": ""40.008,50"",
""Fecha"": ""2021-10-10""
}
],
""UFOs"": [
{
""Valor"": ""30.008,40"",
""Fecha"": ""2021-09-10""
}
]
}";
string singleDataFromApi = #"{
""UFs"": [
{
""Valor"": ""30.008,40"",
""Fecha"": ""2021-09-10""
},
{
""Valor"": ""40.008,50"",
""Fecha"": ""2021-10-10""
}
]
}";
processDataFromApi(multiDataFromApi);
processDataFromApi(singleDataFromApi);
void processDataFromApi(string json)
{
var dataDict = JsonSerializer.Deserialize<Dictionary<string, List<Indicador>>>(json);
if (dataDict.Count == 1)
{
Console.WriteLine("-- Single Key Processing --");
List<Indicador> indicadors = dataDict.Values.First();
indicadors.ForEach(indicador => Console.WriteLine("\t{0}", indicador));
}
else
{
Console.WriteLine("-- Multi Key Processing --");
foreach (var keyValuePair in dataDict)
{
Console.WriteLine($"Processing Key: {keyValuePair.Key}");
List<Indicador> indicadors = keyValuePair.Value;
indicadors.ForEach(indicador => Console.WriteLine("\t{0}",indicador));
}
}
Console.WriteLine("-----------------------------");
}
// Using records because they are brief and come with a good default ToString() method
// You can use regular class if you require
public abstract record IIndicador(string Valor, string Fecha);
public record Indicador(string Valor, string Fecha): IIndicador(Valor, Fecha);
which will produce the following output
-- Multi Key Processing --
Processing Key: UFs
Indicador { Valor = 30.008,40, Fecha = 2021-09-10 }
Indicador { Valor = 40.008,50, Fecha = 2021-10-10 }
Processing Key: UFOs
Indicador { Valor = 30.008,40, Fecha = 2021-09-10 }
-----------------------------
-- Single Key Processing --
Indicador { Valor = 30.008,40, Fecha = 2021-09-10 }
Indicador { Valor = 40.008,50, Fecha = 2021-10-10 }
-----------------------------
Following this example:
https://learn.microsoft.com/en-us/azure/cognitive-services/luis/luis-quickstart-cs-add-utterance
I am trying to send an utterance to my LUIS App.
It keeps on failing with this response message:
{
"error": {
"code": "BadArgument",
"message": "Failed to parse example labeling objects. Parameter name: exampleLabelObjects"
}
}
My input body is:
{
"text": "hi, what can I help you with?",
"intentName": "Help",
"entityLabels": []
}
And according too the link if you send an utterance without any entity labels the above is correct.
The entityLabels field is required. If you don't want to label any
entities, provide an empty list as shown in the following example:
[
{
"text": "go to Seattle",
"intentName": "BookFlight",
"entityLabels": [
{
"entityName": "Location::LocationTo",
"startCharIndex": 6,
"endCharIndex": 12
}
]
},
{
"text": "book a flight",
"intentName": "BookFlight",
"entityLabels": []
}
]
The C# to build the object is as follows:
public class LUISUtterItem
{
public string utterances;
public string text;
public string intentName;
public List<exampleLabelObjects> entityLabels;
}
public class exampleLabelObjects
{
public string entityName;
public int startCharIndex;
public int endCharIndex;
}
I call it using:
LUISUtterItem itm = new LUISUtterItem();
//itm.utterances = materialArray[1];
itm.text = materialArray[1];
itm.intentName = materialArray[2];
itm.entityLabels = new List<exampleLabelObjects>();
I have also tried not including an "entityLabels" object, as well as a string list that just gets initiated with the same result.
Any help will be appreciated.
So it seems like all you have to include in the body is "[]" around it and it worked:
[{
"text": "hi, what can I help you with?",
"intentName": "Help",
"entityLabels": []
}]
I faced the same issue. Solved by sending the body as:
{
"text": "hi",
"intentName": "Greetings"
}
Don't put entityLabel if it is not needed.
I have the following JSON, and I want to take a list of IDs with its values
For example in LINQ something like this: result.Select(x=>x.id)
I tried this:
var inner = outer["pictures"].Value<JArray>().ToList();
I have a list there but with all attributes but I am not able to select just IDs since it is an anonymous list.
outer
{{
"id": "669654603",
"pictures": [
{
"id": "659745-MLA25600661898_052017",
"url": "http://mla-s2-p.mlstatic.com/659745-MLA25600661898_052017-O.jpg",
"secure_url": "https://mla-s2-p.mlstatic.com/659745-MLA25600661898_052017-O.jpg",
"size": "500x365",
"max_size": "625x457",
"quality": ""
},
{
"id": "908422-MLA25658267858_062017",
"url": "http://mla-s2-p.mlstatic.com/908422-MLA25658267858_062017-O.jpg",
"secure_url": "https://mla-s2-p.mlstatic.com/908422-MLA25658267858_062017-O.jpg",
"size": "47x47",
"max_size": "47x47",
"quality": ""
},
{
"id": "794138-MLA25658267889_062017",
"url": "http://mla-s2-p.mlstatic.com/794138-MLA25658267889_062017-O.jpg",
"secure_url": "https://mla-s2-p.mlstatic.com/794138-MLA25658267889_062017-O.jpg",
"size": "40x40",
"max_size": "40x40",
"quality": ""
}
]
}}
When working with Newtonsoft JSON you can do it like this:
var values = JObject.Parse(jsonString)["pictures"].Select(p => p["id"].Value<string>()).ToList();
In order to be valid your json should not contain double curly brackets:
{
"id": "669654603",
"pictures": [ ... ]
}
You can parse it without additional classes:
var ids = JObject.Parse(json)["pictures"].Select(p => (string)p["id"]);
Output:
[
"659745-MLA25600661898_052017",
"908422-MLA25658267858_062017",
"794138-MLA25658267889_062017"
]
Or you can create several classes to hold your json data:
public class Container
{
public List<Picture> Pictures { get; set; }
}
public class Picture
{
public string Id { get; set; }
// you can add other properties here
}
And use strongly-typed parsing:
var ids = JsonConvert.DeserializeObject<Container>(json).Pictures.Select(p => p.Id);
I've got a JSON stream coming back from a server, and I need to search for a specific value of the node "ID" using JSON.net to parse the data.
And I can almost make it work, but not quite because the results coming back are deeply nested in each other -- this is due to the fact that I'm getting a folder structure back. I've boiled the JSON down to a much simpler version. I'm getting this:
{
"data": {
"id": 0,
"name": "",
"childFolders": [{
"id": 19002,
"name": "Locker",
"childFolders": [{
"id": 19003,
"name": "Folder1",
"childFolders": [],
"childComponents": [{
"id": 19005,
"name": "route1",
"state": "STOPPED",
"type": "ROUTE"
}]
}, {
"id": 19004,
"name": "Folder2",
"childFolders": [],
"childComponents": [{
"id": 19008,
"name": "comm1",
"state": "STOPPED",
"type": "COMMUNICATION_POINT"
}, {
"id": 19006,
"name": "route2",
"state": "STOPPED",
"type": "ROUTE"
}, {
"id": 19007,
"name": "route3",
"state": "STOPPED",
"type": "ROUTE"
}]
}],
"childComponents": []
}],
"childComponents": []
},
"error": null
}
I can almost get there by going:
var objects = JObject.Parse(results);
var subobjects = objects["data"]["childFolders"][0]["childFolders"][1];
I can see in the debug view that it'll parse the object, but won't let me search within.
My ultimate goal is to be able to search for "route3" and get back 19007, since that's the ID for that route. I've found some results, but all of them assume you know how far nested the object is. The object I'm searching for could be 2 deep or 20 deep.
My ultimate goal is to be able to search for "route3" and get back 19007
You can use linq and Descendants method of JObject to do it:
var dirs = JObject.Parse(json)
.Descendants()
.Where(x=>x is JObject)
.Where(x=>x["id"]!=null && x["name"]!=null)
.Select(x =>new { ID= (int)x["id"], Name = (string)x["name"] })
.ToList();
var id = dirs.Find(x => x.Name == "route3").ID;
You can use the SelectToken or SelectTokens functions to provide a JPath to search for your desired node. Here is an example that would provide you the route based on name:
JObject.Parse(jsonData)["data"].SelectToken("$..childComponents[?(#.name=='route3')]")
You can find more documentation on JPath here
Simply write a recursive function:
private Thing FindThing(Thing thing, string name)
{
if (thing.name == name)
return thing;
foreach (var subThing in thing.childFolders.Concat(thing.childComponents))
{
var foundSub = FindThing(subThing, name);
if (foundSub != null)
return foundSub;
}
return null;
}
class RootObject
{
public Thing data { get; set; }
}
class Thing
{
public int id { get; set; }
public string name { get; set; }
public List<Thing> childFolders { get; set; } = new List<Thing>();
public List<Thing> childComponents { get; set; } = new List<Thing>();
}
And using it:
var obj = JsonConvert.DeserializeObject<RootObject>(jsonString);
var result = FindThing(obj.data, "route3");