Looping JSON in WebAPI Controller and Add new Property
Clash Royale CLAN TAG#URR8PPP
.everyoneloves__top-leaderboard:empty,.everyoneloves__mid-leaderboard:empty margin-bottom:0;
up vote
2
down vote
favorite
I have a json array that is being passed into a function. Whenever the function comes across a field (call it Field1) in a record with a value that starts with "@!!!@" the function compile them into a list to fire off to another server. I have code that looks like this in the initial function:
public static async Task<HttpResponseMessage> Run(HttpRequestMessage req, TraceWriter log)
dynamic request = await req.Content.ReadAsAsync<dynamic>();
JObject data = (JObject)request;
var directive = data["Directive"];
var json = data.Last.First;
string url = null;
if (directive.ToString() == "D")
url = "registry/get";
else if (directive.ToString() == "S")
url = "registry/sanitize";
JArray payloadArray = (JArray)json;
string newToken = null;
List<JObject> objList = new List<JObject>();
for (int i = 0; i <= payloadArray.Count() - 1; i++)
string newJson = null;
foreach (var prop in payloadArray[i])
newJson = newJson + prop.ToString() + ",";
if (prop.ToString().Contains("@!!!@"))
JObject newProp = new JObject();
newProp.Add(prop);
newJson = newJson + """ + newProp.Properties().First().Name + "":"sanitize
objList.Add(JObject.Parse("" + newJson + ""));
string outGoingPayload = ""Registry":[" + newToken + "]";
var content = new StringContent(outGoingPayload.ToString(), Encoding.UTF8, "application/json");
HttpResponseMessage response = MakeRequest(outGoingPayload.ToString());
var responseBodyAsText = response.Content.ReadAsStringAsync();
JObject responseJson = JObject.Parse(responseBodyAsText.Result);
int counter = 0;
foreach(JObject item in objList)
foreach(var itm in item)
@!!!@"))
foreach(var resItem in responseJson)
if (resItem.Value[counter]["ProcessId"].ToString() == itm.Value.ToString().Replace("sanitize
string jsonStr = null;
foreach (var val in objList)
jsonStr = jsonStr + val + ",";
jsonStr = "[" + jsonStr.TrimEnd(',') + "]";
var returnArray = JsonConvert.DeserializeObject(jsonStr);
return req.CreateResponse(HttpStatusCode.OK, "returnArray");
For a Json payload of 1000 records this take 5000ms to run. What can I do to improve performance here? Setup of the system is the payload passed into the function will contain all records, I must build up a new payload to pass into the remote service to get corresponding values. I do this as one HttpClient request. So this means I loop the initial payload, build up the new payload, call the remove service, return all matches and loop the initial payload and add the extra field where appropriate. I am trying to get this function to return a bit faster. I have tried using Linq to JSON I have tried treating the json as a string. The code I have posted seems to be the fastest. I can provide more information if needed.
Sample payload to send to this function:
"Directive":"S",
"Wrapper":[
"Field1":"Apple",
"Field2":"Peach",
"Field3":"@!!!@008d613d1ca60885468bf274daa693cc778430fc8a539bdf2e7dc2dec88cd922",
"Field4":"Kiwi"
,
"Field1":"Apple2",
"Field2":"Peach2",
"Field3":"@!!!@17e9ad37968e25893e96855ba3d633e250a401a6584b2bc9c7288f9fc458a9b6",
"Field4":"Kiwi2"
]
Sample to send the intermediate function (I cannot touch this one but it's already optimized) My function should build this from the above payload:
"Wrapper":[
"Token":"@!!!@17e9ad37968e25893e96855ba3d633e250a401a6584b2bc9c7288f9fc458a9b6",
"Token":"@!!!@008d613d1ca60885468bf274daa693cc778430fc8a539bdf2e7dc2dec88cd922"
]
Return from intermediate service:
"Wrapper":[
"Token":"@!!!@17e9ad37968e25893e96855ba3d633e250a401a6584b2bc9c7288f9fc458a9b6", "Value":"test",
"Token":"@!!!@008d613d1ca60885468bf274daa693cc778430fc8a539bdf2e7dc2dec88cd922", "Value":"test2"
]
Back in my function both the original payload and the return payload from the intermediate function should be merged and returned like this:
"Wrapper":[
"Field1":"Apple",
"Field2":"Peach",
"Field3":"@!!!@008d613d1ca60885468bf274daa693cc778430fc8a539bdf2e7dc2dec88cd922",
"@Field3":"test2",
"Field4":"Kiwi"
,
"Field1":"Apple2",
"Field2":"Peach2",
"Field3":"@!!!@17e9ad37968e25893e96855ba3d633e250a401a6584b2bc9c7288f9fc458a9b6 ",
"@Field3":"test"
"Field4":"Kiwi2"
]
c# performance json json.net
 |Â
show 11 more comments
up vote
2
down vote
favorite
I have a json array that is being passed into a function. Whenever the function comes across a field (call it Field1) in a record with a value that starts with "@!!!@" the function compile them into a list to fire off to another server. I have code that looks like this in the initial function:
public static async Task<HttpResponseMessage> Run(HttpRequestMessage req, TraceWriter log)
dynamic request = await req.Content.ReadAsAsync<dynamic>();
JObject data = (JObject)request;
var directive = data["Directive"];
var json = data.Last.First;
string url = null;
if (directive.ToString() == "D")
url = "registry/get";
else if (directive.ToString() == "S")
url = "registry/sanitize";
JArray payloadArray = (JArray)json;
string newToken = null;
List<JObject> objList = new List<JObject>();
for (int i = 0; i <= payloadArray.Count() - 1; i++)
string newJson = null;
foreach (var prop in payloadArray[i])
newJson = newJson + prop.ToString() + ",";
if (prop.ToString().Contains("@!!!@"))
JObject newProp = new JObject();
newProp.Add(prop);
newJson = newJson + """ + newProp.Properties().First().Name + "":"sanitize
objList.Add(JObject.Parse("" + newJson + ""));
string outGoingPayload = ""Registry":[" + newToken + "]";
var content = new StringContent(outGoingPayload.ToString(), Encoding.UTF8, "application/json");
HttpResponseMessage response = MakeRequest(outGoingPayload.ToString());
var responseBodyAsText = response.Content.ReadAsStringAsync();
JObject responseJson = JObject.Parse(responseBodyAsText.Result);
int counter = 0;
foreach(JObject item in objList)
foreach(var itm in item)
@!!!@"))
foreach(var resItem in responseJson)
if (resItem.Value[counter]["ProcessId"].ToString() == itm.Value.ToString().Replace("sanitize
string jsonStr = null;
foreach (var val in objList)
jsonStr = jsonStr + val + ",";
jsonStr = "[" + jsonStr.TrimEnd(',') + "]";
var returnArray = JsonConvert.DeserializeObject(jsonStr);
return req.CreateResponse(HttpStatusCode.OK, "returnArray");
For a Json payload of 1000 records this take 5000ms to run. What can I do to improve performance here? Setup of the system is the payload passed into the function will contain all records, I must build up a new payload to pass into the remote service to get corresponding values. I do this as one HttpClient request. So this means I loop the initial payload, build up the new payload, call the remove service, return all matches and loop the initial payload and add the extra field where appropriate. I am trying to get this function to return a bit faster. I have tried using Linq to JSON I have tried treating the json as a string. The code I have posted seems to be the fastest. I can provide more information if needed.
Sample payload to send to this function:
"Directive":"S",
"Wrapper":[
"Field1":"Apple",
"Field2":"Peach",
"Field3":"@!!!@008d613d1ca60885468bf274daa693cc778430fc8a539bdf2e7dc2dec88cd922",
"Field4":"Kiwi"
,
"Field1":"Apple2",
"Field2":"Peach2",
"Field3":"@!!!@17e9ad37968e25893e96855ba3d633e250a401a6584b2bc9c7288f9fc458a9b6",
"Field4":"Kiwi2"
]
Sample to send the intermediate function (I cannot touch this one but it's already optimized) My function should build this from the above payload:
"Wrapper":[
"Token":"@!!!@17e9ad37968e25893e96855ba3d633e250a401a6584b2bc9c7288f9fc458a9b6",
"Token":"@!!!@008d613d1ca60885468bf274daa693cc778430fc8a539bdf2e7dc2dec88cd922"
]
Return from intermediate service:
"Wrapper":[
"Token":"@!!!@17e9ad37968e25893e96855ba3d633e250a401a6584b2bc9c7288f9fc458a9b6", "Value":"test",
"Token":"@!!!@008d613d1ca60885468bf274daa693cc778430fc8a539bdf2e7dc2dec88cd922", "Value":"test2"
]
Back in my function both the original payload and the return payload from the intermediate function should be merged and returned like this:
"Wrapper":[
"Field1":"Apple",
"Field2":"Peach",
"Field3":"@!!!@008d613d1ca60885468bf274daa693cc778430fc8a539bdf2e7dc2dec88cd922",
"@Field3":"test2",
"Field4":"Kiwi"
,
"Field1":"Apple2",
"Field2":"Peach2",
"Field3":"@!!!@17e9ad37968e25893e96855ba3d633e250a401a6584b2bc9c7288f9fc458a9b6 ",
"@Field3":"test"
"Field4":"Kiwi2"
]
c# performance json json.net
Please post the complete method, not a random snippet. If possible the class.
â t3chb0t
Jul 13 at 17:55
sure give me a moment and I will do that.... just FYI the bottleneck is in the first function the remote service called cannot be modified and is already optimized. Let me upload the entire class.
â VinnyGuitara
Jul 13 at 17:56
Was only able to put the function in not the whole class. The only other method in the class is the call to the remote service.
â VinnyGuitara
Jul 13 at 18:02
This looks much better now ;-) I think the whole class isn't necessary here. The method provides enough context.
â t3chb0t
Jul 13 at 18:04
1
@t3chb0t - I was able to add the payload/response example JSON... Hopefully that helps.
â VinnyGuitara
Jul 16 at 14:00
 |Â
show 11 more comments
up vote
2
down vote
favorite
up vote
2
down vote
favorite
I have a json array that is being passed into a function. Whenever the function comes across a field (call it Field1) in a record with a value that starts with "@!!!@" the function compile them into a list to fire off to another server. I have code that looks like this in the initial function:
public static async Task<HttpResponseMessage> Run(HttpRequestMessage req, TraceWriter log)
dynamic request = await req.Content.ReadAsAsync<dynamic>();
JObject data = (JObject)request;
var directive = data["Directive"];
var json = data.Last.First;
string url = null;
if (directive.ToString() == "D")
url = "registry/get";
else if (directive.ToString() == "S")
url = "registry/sanitize";
JArray payloadArray = (JArray)json;
string newToken = null;
List<JObject> objList = new List<JObject>();
for (int i = 0; i <= payloadArray.Count() - 1; i++)
string newJson = null;
foreach (var prop in payloadArray[i])
newJson = newJson + prop.ToString() + ",";
if (prop.ToString().Contains("@!!!@"))
JObject newProp = new JObject();
newProp.Add(prop);
newJson = newJson + """ + newProp.Properties().First().Name + "":"sanitize
objList.Add(JObject.Parse("" + newJson + ""));
string outGoingPayload = ""Registry":[" + newToken + "]";
var content = new StringContent(outGoingPayload.ToString(), Encoding.UTF8, "application/json");
HttpResponseMessage response = MakeRequest(outGoingPayload.ToString());
var responseBodyAsText = response.Content.ReadAsStringAsync();
JObject responseJson = JObject.Parse(responseBodyAsText.Result);
int counter = 0;
foreach(JObject item in objList)
foreach(var itm in item)
@!!!@"))
foreach(var resItem in responseJson)
if (resItem.Value[counter]["ProcessId"].ToString() == itm.Value.ToString().Replace("sanitize
string jsonStr = null;
foreach (var val in objList)
jsonStr = jsonStr + val + ",";
jsonStr = "[" + jsonStr.TrimEnd(',') + "]";
var returnArray = JsonConvert.DeserializeObject(jsonStr);
return req.CreateResponse(HttpStatusCode.OK, "returnArray");
For a Json payload of 1000 records this take 5000ms to run. What can I do to improve performance here? Setup of the system is the payload passed into the function will contain all records, I must build up a new payload to pass into the remote service to get corresponding values. I do this as one HttpClient request. So this means I loop the initial payload, build up the new payload, call the remove service, return all matches and loop the initial payload and add the extra field where appropriate. I am trying to get this function to return a bit faster. I have tried using Linq to JSON I have tried treating the json as a string. The code I have posted seems to be the fastest. I can provide more information if needed.
Sample payload to send to this function:
"Directive":"S",
"Wrapper":[
"Field1":"Apple",
"Field2":"Peach",
"Field3":"@!!!@008d613d1ca60885468bf274daa693cc778430fc8a539bdf2e7dc2dec88cd922",
"Field4":"Kiwi"
,
"Field1":"Apple2",
"Field2":"Peach2",
"Field3":"@!!!@17e9ad37968e25893e96855ba3d633e250a401a6584b2bc9c7288f9fc458a9b6",
"Field4":"Kiwi2"
]
Sample to send the intermediate function (I cannot touch this one but it's already optimized) My function should build this from the above payload:
"Wrapper":[
"Token":"@!!!@17e9ad37968e25893e96855ba3d633e250a401a6584b2bc9c7288f9fc458a9b6",
"Token":"@!!!@008d613d1ca60885468bf274daa693cc778430fc8a539bdf2e7dc2dec88cd922"
]
Return from intermediate service:
"Wrapper":[
"Token":"@!!!@17e9ad37968e25893e96855ba3d633e250a401a6584b2bc9c7288f9fc458a9b6", "Value":"test",
"Token":"@!!!@008d613d1ca60885468bf274daa693cc778430fc8a539bdf2e7dc2dec88cd922", "Value":"test2"
]
Back in my function both the original payload and the return payload from the intermediate function should be merged and returned like this:
"Wrapper":[
"Field1":"Apple",
"Field2":"Peach",
"Field3":"@!!!@008d613d1ca60885468bf274daa693cc778430fc8a539bdf2e7dc2dec88cd922",
"@Field3":"test2",
"Field4":"Kiwi"
,
"Field1":"Apple2",
"Field2":"Peach2",
"Field3":"@!!!@17e9ad37968e25893e96855ba3d633e250a401a6584b2bc9c7288f9fc458a9b6 ",
"@Field3":"test"
"Field4":"Kiwi2"
]
c# performance json json.net
I have a json array that is being passed into a function. Whenever the function comes across a field (call it Field1) in a record with a value that starts with "@!!!@" the function compile them into a list to fire off to another server. I have code that looks like this in the initial function:
public static async Task<HttpResponseMessage> Run(HttpRequestMessage req, TraceWriter log)
dynamic request = await req.Content.ReadAsAsync<dynamic>();
JObject data = (JObject)request;
var directive = data["Directive"];
var json = data.Last.First;
string url = null;
if (directive.ToString() == "D")
url = "registry/get";
else if (directive.ToString() == "S")
url = "registry/sanitize";
JArray payloadArray = (JArray)json;
string newToken = null;
List<JObject> objList = new List<JObject>();
for (int i = 0; i <= payloadArray.Count() - 1; i++)
string newJson = null;
foreach (var prop in payloadArray[i])
newJson = newJson + prop.ToString() + ",";
if (prop.ToString().Contains("@!!!@"))
JObject newProp = new JObject();
newProp.Add(prop);
newJson = newJson + """ + newProp.Properties().First().Name + "":"sanitize
objList.Add(JObject.Parse("" + newJson + ""));
string outGoingPayload = ""Registry":[" + newToken + "]";
var content = new StringContent(outGoingPayload.ToString(), Encoding.UTF8, "application/json");
HttpResponseMessage response = MakeRequest(outGoingPayload.ToString());
var responseBodyAsText = response.Content.ReadAsStringAsync();
JObject responseJson = JObject.Parse(responseBodyAsText.Result);
int counter = 0;
foreach(JObject item in objList)
foreach(var itm in item)
@!!!@"))
foreach(var resItem in responseJson)
if (resItem.Value[counter]["ProcessId"].ToString() == itm.Value.ToString().Replace("sanitize
string jsonStr = null;
foreach (var val in objList)
jsonStr = jsonStr + val + ",";
jsonStr = "[" + jsonStr.TrimEnd(',') + "]";
var returnArray = JsonConvert.DeserializeObject(jsonStr);
return req.CreateResponse(HttpStatusCode.OK, "returnArray");
For a Json payload of 1000 records this take 5000ms to run. What can I do to improve performance here? Setup of the system is the payload passed into the function will contain all records, I must build up a new payload to pass into the remote service to get corresponding values. I do this as one HttpClient request. So this means I loop the initial payload, build up the new payload, call the remove service, return all matches and loop the initial payload and add the extra field where appropriate. I am trying to get this function to return a bit faster. I have tried using Linq to JSON I have tried treating the json as a string. The code I have posted seems to be the fastest. I can provide more information if needed.
Sample payload to send to this function:
"Directive":"S",
"Wrapper":[
"Field1":"Apple",
"Field2":"Peach",
"Field3":"@!!!@008d613d1ca60885468bf274daa693cc778430fc8a539bdf2e7dc2dec88cd922",
"Field4":"Kiwi"
,
"Field1":"Apple2",
"Field2":"Peach2",
"Field3":"@!!!@17e9ad37968e25893e96855ba3d633e250a401a6584b2bc9c7288f9fc458a9b6",
"Field4":"Kiwi2"
]
Sample to send the intermediate function (I cannot touch this one but it's already optimized) My function should build this from the above payload:
"Wrapper":[
"Token":"@!!!@17e9ad37968e25893e96855ba3d633e250a401a6584b2bc9c7288f9fc458a9b6",
"Token":"@!!!@008d613d1ca60885468bf274daa693cc778430fc8a539bdf2e7dc2dec88cd922"
]
Return from intermediate service:
"Wrapper":[
"Token":"@!!!@17e9ad37968e25893e96855ba3d633e250a401a6584b2bc9c7288f9fc458a9b6", "Value":"test",
"Token":"@!!!@008d613d1ca60885468bf274daa693cc778430fc8a539bdf2e7dc2dec88cd922", "Value":"test2"
]
Back in my function both the original payload and the return payload from the intermediate function should be merged and returned like this:
"Wrapper":[
"Field1":"Apple",
"Field2":"Peach",
"Field3":"@!!!@008d613d1ca60885468bf274daa693cc778430fc8a539bdf2e7dc2dec88cd922",
"@Field3":"test2",
"Field4":"Kiwi"
,
"Field1":"Apple2",
"Field2":"Peach2",
"Field3":"@!!!@17e9ad37968e25893e96855ba3d633e250a401a6584b2bc9c7288f9fc458a9b6 ",
"@Field3":"test"
"Field4":"Kiwi2"
]
c# performance json json.net
edited Jul 16 at 14:07
asked Jul 13 at 17:54
VinnyGuitara
12911
12911
Please post the complete method, not a random snippet. If possible the class.
â t3chb0t
Jul 13 at 17:55
sure give me a moment and I will do that.... just FYI the bottleneck is in the first function the remote service called cannot be modified and is already optimized. Let me upload the entire class.
â VinnyGuitara
Jul 13 at 17:56
Was only able to put the function in not the whole class. The only other method in the class is the call to the remote service.
â VinnyGuitara
Jul 13 at 18:02
This looks much better now ;-) I think the whole class isn't necessary here. The method provides enough context.
â t3chb0t
Jul 13 at 18:04
1
@t3chb0t - I was able to add the payload/response example JSON... Hopefully that helps.
â VinnyGuitara
Jul 16 at 14:00
 |Â
show 11 more comments
Please post the complete method, not a random snippet. If possible the class.
â t3chb0t
Jul 13 at 17:55
sure give me a moment and I will do that.... just FYI the bottleneck is in the first function the remote service called cannot be modified and is already optimized. Let me upload the entire class.
â VinnyGuitara
Jul 13 at 17:56
Was only able to put the function in not the whole class. The only other method in the class is the call to the remote service.
â VinnyGuitara
Jul 13 at 18:02
This looks much better now ;-) I think the whole class isn't necessary here. The method provides enough context.
â t3chb0t
Jul 13 at 18:04
1
@t3chb0t - I was able to add the payload/response example JSON... Hopefully that helps.
â VinnyGuitara
Jul 16 at 14:00
Please post the complete method, not a random snippet. If possible the class.
â t3chb0t
Jul 13 at 17:55
Please post the complete method, not a random snippet. If possible the class.
â t3chb0t
Jul 13 at 17:55
sure give me a moment and I will do that.... just FYI the bottleneck is in the first function the remote service called cannot be modified and is already optimized. Let me upload the entire class.
â VinnyGuitara
Jul 13 at 17:56
sure give me a moment and I will do that.... just FYI the bottleneck is in the first function the remote service called cannot be modified and is already optimized. Let me upload the entire class.
â VinnyGuitara
Jul 13 at 17:56
Was only able to put the function in not the whole class. The only other method in the class is the call to the remote service.
â VinnyGuitara
Jul 13 at 18:02
Was only able to put the function in not the whole class. The only other method in the class is the call to the remote service.
â VinnyGuitara
Jul 13 at 18:02
This looks much better now ;-) I think the whole class isn't necessary here. The method provides enough context.
â t3chb0t
Jul 13 at 18:04
This looks much better now ;-) I think the whole class isn't necessary here. The method provides enough context.
â t3chb0t
Jul 13 at 18:04
1
1
@t3chb0t - I was able to add the payload/response example JSON... Hopefully that helps.
â VinnyGuitara
Jul 16 at 14:00
@t3chb0t - I was able to add the payload/response example JSON... Hopefully that helps.
â VinnyGuitara
Jul 16 at 14:00
 |Â
show 11 more comments
1 Answer
1
active
oldest
votes
up vote
2
down vote
accepted
Here are what in my opinion are the primary areas of concern.
Misuse of Json.NET
Code like JObject.Parse("" + newJson + "")
is redundant. You are manually forming a JSON string and then deserialising it back into a JObject. You can just build JTokens directly, avoiding the cost of deserialization and having to mess around with formatting.
Inefficient Token Replacement
After the service call, you update the original items very inefficiently. Lets say you have 1000 items each with 3 tokenised fields. That would be 3000 results from your service call. Your code iterates through all 3000 results for each of the 3000 tokens, resulting in a total of ~9000000 iterations. IâÂÂll show you below how to reduce this to just 3000.
A Possible Solution
If you create some classes to deserialize to/from, the code will be much easier to work with, removing the need to deal with JTokens
at all. To fix your 9 million iterations problem, you could use a dictionary to create a lookup table when you initially loop over the properties. The key could be the token, and the value could be a reference to the item that needs to be updated. Then once you have your token values, you just need to iterate over them, updating the dictionary (fast). I've put a console app together here that works with your example JSON to demonstrate. The key parts are as follows.
Form service request and lookup table
foreach (var item in inputData.Wrapper)
foreach (var kvp in item.Where(property => property.Value.StartsWith("@!!!@")))
propertiesLookup[kvp.Value] = new ItemUpdate
Properties = item,
UpdateKey = kvp.Key
;
propertiesRequest.Wrapper.Add(new PropertySearch
Token = kvp.Value
);
Use lookup table to add tokenized fields to items
foreach (var item in intermediateData.Wrapper)
var itemToUpdate = propertiesLookup[item.Token];
itemToUpdate.Properties[$"@itemToUpdate.UpdateKey"] = item.Value;
It would be much cooler if you included the example code in your answer.
â t3chb0t
Jul 25 at 17:22
Thanks so much for your suggestions and help on this. I am going to take a look at this attachment now.
â VinnyGuitara
Jul 25 at 22:22
add a comment |Â
1 Answer
1
active
oldest
votes
1 Answer
1
active
oldest
votes
active
oldest
votes
active
oldest
votes
up vote
2
down vote
accepted
Here are what in my opinion are the primary areas of concern.
Misuse of Json.NET
Code like JObject.Parse("" + newJson + "")
is redundant. You are manually forming a JSON string and then deserialising it back into a JObject. You can just build JTokens directly, avoiding the cost of deserialization and having to mess around with formatting.
Inefficient Token Replacement
After the service call, you update the original items very inefficiently. Lets say you have 1000 items each with 3 tokenised fields. That would be 3000 results from your service call. Your code iterates through all 3000 results for each of the 3000 tokens, resulting in a total of ~9000000 iterations. IâÂÂll show you below how to reduce this to just 3000.
A Possible Solution
If you create some classes to deserialize to/from, the code will be much easier to work with, removing the need to deal with JTokens
at all. To fix your 9 million iterations problem, you could use a dictionary to create a lookup table when you initially loop over the properties. The key could be the token, and the value could be a reference to the item that needs to be updated. Then once you have your token values, you just need to iterate over them, updating the dictionary (fast). I've put a console app together here that works with your example JSON to demonstrate. The key parts are as follows.
Form service request and lookup table
foreach (var item in inputData.Wrapper)
foreach (var kvp in item.Where(property => property.Value.StartsWith("@!!!@")))
propertiesLookup[kvp.Value] = new ItemUpdate
Properties = item,
UpdateKey = kvp.Key
;
propertiesRequest.Wrapper.Add(new PropertySearch
Token = kvp.Value
);
Use lookup table to add tokenized fields to items
foreach (var item in intermediateData.Wrapper)
var itemToUpdate = propertiesLookup[item.Token];
itemToUpdate.Properties[$"@itemToUpdate.UpdateKey"] = item.Value;
It would be much cooler if you included the example code in your answer.
â t3chb0t
Jul 25 at 17:22
Thanks so much for your suggestions and help on this. I am going to take a look at this attachment now.
â VinnyGuitara
Jul 25 at 22:22
add a comment |Â
up vote
2
down vote
accepted
Here are what in my opinion are the primary areas of concern.
Misuse of Json.NET
Code like JObject.Parse("" + newJson + "")
is redundant. You are manually forming a JSON string and then deserialising it back into a JObject. You can just build JTokens directly, avoiding the cost of deserialization and having to mess around with formatting.
Inefficient Token Replacement
After the service call, you update the original items very inefficiently. Lets say you have 1000 items each with 3 tokenised fields. That would be 3000 results from your service call. Your code iterates through all 3000 results for each of the 3000 tokens, resulting in a total of ~9000000 iterations. IâÂÂll show you below how to reduce this to just 3000.
A Possible Solution
If you create some classes to deserialize to/from, the code will be much easier to work with, removing the need to deal with JTokens
at all. To fix your 9 million iterations problem, you could use a dictionary to create a lookup table when you initially loop over the properties. The key could be the token, and the value could be a reference to the item that needs to be updated. Then once you have your token values, you just need to iterate over them, updating the dictionary (fast). I've put a console app together here that works with your example JSON to demonstrate. The key parts are as follows.
Form service request and lookup table
foreach (var item in inputData.Wrapper)
foreach (var kvp in item.Where(property => property.Value.StartsWith("@!!!@")))
propertiesLookup[kvp.Value] = new ItemUpdate
Properties = item,
UpdateKey = kvp.Key
;
propertiesRequest.Wrapper.Add(new PropertySearch
Token = kvp.Value
);
Use lookup table to add tokenized fields to items
foreach (var item in intermediateData.Wrapper)
var itemToUpdate = propertiesLookup[item.Token];
itemToUpdate.Properties[$"@itemToUpdate.UpdateKey"] = item.Value;
It would be much cooler if you included the example code in your answer.
â t3chb0t
Jul 25 at 17:22
Thanks so much for your suggestions and help on this. I am going to take a look at this attachment now.
â VinnyGuitara
Jul 25 at 22:22
add a comment |Â
up vote
2
down vote
accepted
up vote
2
down vote
accepted
Here are what in my opinion are the primary areas of concern.
Misuse of Json.NET
Code like JObject.Parse("" + newJson + "")
is redundant. You are manually forming a JSON string and then deserialising it back into a JObject. You can just build JTokens directly, avoiding the cost of deserialization and having to mess around with formatting.
Inefficient Token Replacement
After the service call, you update the original items very inefficiently. Lets say you have 1000 items each with 3 tokenised fields. That would be 3000 results from your service call. Your code iterates through all 3000 results for each of the 3000 tokens, resulting in a total of ~9000000 iterations. IâÂÂll show you below how to reduce this to just 3000.
A Possible Solution
If you create some classes to deserialize to/from, the code will be much easier to work with, removing the need to deal with JTokens
at all. To fix your 9 million iterations problem, you could use a dictionary to create a lookup table when you initially loop over the properties. The key could be the token, and the value could be a reference to the item that needs to be updated. Then once you have your token values, you just need to iterate over them, updating the dictionary (fast). I've put a console app together here that works with your example JSON to demonstrate. The key parts are as follows.
Form service request and lookup table
foreach (var item in inputData.Wrapper)
foreach (var kvp in item.Where(property => property.Value.StartsWith("@!!!@")))
propertiesLookup[kvp.Value] = new ItemUpdate
Properties = item,
UpdateKey = kvp.Key
;
propertiesRequest.Wrapper.Add(new PropertySearch
Token = kvp.Value
);
Use lookup table to add tokenized fields to items
foreach (var item in intermediateData.Wrapper)
var itemToUpdate = propertiesLookup[item.Token];
itemToUpdate.Properties[$"@itemToUpdate.UpdateKey"] = item.Value;
Here are what in my opinion are the primary areas of concern.
Misuse of Json.NET
Code like JObject.Parse("" + newJson + "")
is redundant. You are manually forming a JSON string and then deserialising it back into a JObject. You can just build JTokens directly, avoiding the cost of deserialization and having to mess around with formatting.
Inefficient Token Replacement
After the service call, you update the original items very inefficiently. Lets say you have 1000 items each with 3 tokenised fields. That would be 3000 results from your service call. Your code iterates through all 3000 results for each of the 3000 tokens, resulting in a total of ~9000000 iterations. IâÂÂll show you below how to reduce this to just 3000.
A Possible Solution
If you create some classes to deserialize to/from, the code will be much easier to work with, removing the need to deal with JTokens
at all. To fix your 9 million iterations problem, you could use a dictionary to create a lookup table when you initially loop over the properties. The key could be the token, and the value could be a reference to the item that needs to be updated. Then once you have your token values, you just need to iterate over them, updating the dictionary (fast). I've put a console app together here that works with your example JSON to demonstrate. The key parts are as follows.
Form service request and lookup table
foreach (var item in inputData.Wrapper)
foreach (var kvp in item.Where(property => property.Value.StartsWith("@!!!@")))
propertiesLookup[kvp.Value] = new ItemUpdate
Properties = item,
UpdateKey = kvp.Key
;
propertiesRequest.Wrapper.Add(new PropertySearch
Token = kvp.Value
);
Use lookup table to add tokenized fields to items
foreach (var item in intermediateData.Wrapper)
var itemToUpdate = propertiesLookup[item.Token];
itemToUpdate.Properties[$"@itemToUpdate.UpdateKey"] = item.Value;
edited Jul 27 at 7:53
answered Jul 25 at 17:17
Matt Cole
763410
763410
It would be much cooler if you included the example code in your answer.
â t3chb0t
Jul 25 at 17:22
Thanks so much for your suggestions and help on this. I am going to take a look at this attachment now.
â VinnyGuitara
Jul 25 at 22:22
add a comment |Â
It would be much cooler if you included the example code in your answer.
â t3chb0t
Jul 25 at 17:22
Thanks so much for your suggestions and help on this. I am going to take a look at this attachment now.
â VinnyGuitara
Jul 25 at 22:22
It would be much cooler if you included the example code in your answer.
â t3chb0t
Jul 25 at 17:22
It would be much cooler if you included the example code in your answer.
â t3chb0t
Jul 25 at 17:22
Thanks so much for your suggestions and help on this. I am going to take a look at this attachment now.
â VinnyGuitara
Jul 25 at 22:22
Thanks so much for your suggestions and help on this. I am going to take a look at this attachment now.
â VinnyGuitara
Jul 25 at 22:22
add a comment |Â
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f198445%2flooping-json-in-webapi-controller-and-add-new-property%23new-answer', 'question_page');
);
Post as a guest
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Please post the complete method, not a random snippet. If possible the class.
â t3chb0t
Jul 13 at 17:55
sure give me a moment and I will do that.... just FYI the bottleneck is in the first function the remote service called cannot be modified and is already optimized. Let me upload the entire class.
â VinnyGuitara
Jul 13 at 17:56
Was only able to put the function in not the whole class. The only other method in the class is the call to the remote service.
â VinnyGuitara
Jul 13 at 18:02
This looks much better now ;-) I think the whole class isn't necessary here. The method provides enough context.
â t3chb0t
Jul 13 at 18:04
1
@t3chb0t - I was able to add the payload/response example JSON... Hopefully that helps.
â VinnyGuitara
Jul 16 at 14:00