Based on our discussion in the first solution, I have posted this as a separate solution as it is a very different approach and more involved then the first solution.
Okay, So you want to convert all JSON Properties & values to a
Dictionary<string, object>
. Then you want to see if there are any matches with blocked keywords. You also want to store blocked keywords in a
HashSet<T>
.
To do the comparison, we can not use the Linq method
Intersect
. The reason for this can be seen in the output below. you can not assume that the value will only be a blocked keyword, usually any SQL command has more as required by the command syntax.
Here is how it can be done:
string json = @"{
""Id"": null,
""FName"": ""create"",
""LName"": ""Denny"",
""DateofJoining"": null,
""Date"": ""2023-08-01T00:00:00"",
""CreatedBy"": ""ICC0000389"",
""levels"": {
""RoleId"": ""0"",
""RoleName"": ""select"",
""IsActive"": false,
""CreatedDate"": null,
""CreatedBy"": ""Admin""
},
""functionalities"": [
{
""levelID"": 0,
""levelName"": ""create""
}
],
""functionalityList"": []
}";
Dictionary<string, object> jsonDict = JsonConvert.DeserializeObject<Dictionary<string, object>>(json);
Console.WriteLine("Converted JSON to Dictionary:");
foreach (var kvp in jsonDict)
{
Console.WriteLine($"> {kvp.Key}: {kvp.Value}");
}
HashSet<string> blocked = new HashSet<string>
{
"create",
"update",
"union",
"select"
};
List<string> jsonValues = jsonDict
.Select(kvp => kvp.Value)
.OfType<string>()
.Select(x => x.ToLower())
.ToList();
Console.WriteLine();
Console.WriteLine("Matches:");
var matches = jsonValues.Where(j => blocked.Any(j.Contains));
foreach (string match in matches)
{
Console.WriteLine($"> {match}");
}
And here is the output:
Converted JSON to Dictionary:
> Id:
> FName: create
> LName: Denny
> DateofJoining:
> Date: 1/08/2023 12:00:00 AM
> CreatedBy: ICC0000389
> levels: {
"RoleId": "0",
"RoleName": "select",
"IsActive": false,
"CreatedDate": null,
"CreatedBy": "Admin"
}
> functionalities: [
{
"levelID": 0,
"levelName": "create"
}
]
> functionalityList: []
Matches:
> create
in the section labelled
Converted JSON to Dictionary, I have output a prefix marker ">" so we can see what each key & value consists of. Note:
> levels: {
"RoleId": "0",
"RoleName": "select",
"IsActive": false,
"CreatedDate": null,
"CreatedBy": "Admin"
}
Here we can see that children in the data structure do not automatically deserialize. More work is required. We are not looking for exact matches, so this is okay.
UPDATE
If you want to extract every Property & Values, then you need to manually walk the Json tree structure:
using System;
using Newtonsoft.Json.Linq;
using System.Collections.Generic;
using System.Linq;
internal class Program
{
private static void Main(string[] args)
{
string json = @"
{
""Id"": null,
""FName"": ""create"",
""LName"": ""Denny"",
""DateofJoining"": null,
""Date"": ""2023-08-01T00:00:00"",
""CreatedBy"": ""ICC0000389"",
""levels"": {
""RoleId"": ""0"",
""RoleName"": ""select"",
""IsActive"": false,
""CreatedDate"": null,
""CreatedBy"": ""Admin""
},
""functionalities"": [{
""levelID"": 0,
""levelName"": ""create""
}
],
""functionalityList"": []
}";
Dictionary<string, object> jsonDict = ParseJsonToDictionary(json);
foreach (KeyValuePair<string, object> kvp in jsonDict)
{
Console.WriteLine($"> {kvp.Key}: {kvp.Value}");
}
HashSet<string> blocked = new HashSet<string>
{
"create",
"update",
"union",
"select"
};
List<string> jsonValues = jsonDict
.Select(kvp => kvp.Value)
.OfType<string>()
.Select(x => x.ToLower())
.ToList();
Console.WriteLine();
Console.WriteLine("Matches:");
IEnumerable<string> matches = jsonValues.Where(j => blocked.Any(j.Contains));
foreach (string match in matches)
{
Console.WriteLine($"> {match}");
}
Console.WriteLine();
Console.WriteLine("Matches using intersect:");
IEnumerable<string> matches2 = jsonValues.Intersect(blocked);
foreach (string match in matches2)
{
Console.WriteLine($"> {match}");
}
Console.ReadKey();
}
private static Dictionary<string, object> ParseJsonToDictionary(string json)
{
Dictionary<string, object> dictionary = new Dictionary<string, object>();
JObject jObject = JObject.Parse(json);
ParseJObject(jObject, dictionary);
return dictionary;
}
private static void ParseJObject(JObject jObject, Dictionary<string, object> dictionary)
{
foreach (JProperty property in jObject.Properties())
{
switch (property.Value.Type)
{
case JTokenType.Array:
foreach (JToken item in property.Value)
{
if (item.Type == JTokenType.Object)
{
ParseJObject(item.Value<JObject>(), dictionary);
}
}
break;
case JTokenType.Object:
ParseJObject(property.Value.Value<JObject>(), dictionary);
break;
default:
dictionary[property.Name] = ParseJValue(property.Value);
break;
}
}
}
private static object ParseJValue(JToken jValue)
{
switch (jValue.Type)
{
case JTokenType.Object:
{
Dictionary<string, object> nestedDictionary = new Dictionary<string, object>();
ParseJObject(jValue as JObject, nestedDictionary);
return nestedDictionary;
}
case JTokenType.Array:
{
return jValue.Select(ParseJValue).ToList();
}
default:
return (jValue as JValue)?.Value;
}
}
}
Now, I
highly recommend not to use the Linq
Intersect
method as it is an
exact match. Reasons given above. But for the sake of this exercise, I have added how to do it in the code just above.
Here is the output:
> Id:
> FName: create
> LName: Denny
> DateofJoining:
> Date: 1/08/2023 12:00:00 AM
> CreatedBy: Admin
> RoleId: 0
> RoleName: select
> IsActive: False
> CreatedDate:
> levelID: 0
> levelName: create
Matches:
> create
> select
> create
Matches using intersect:
> create
> select