Can Json Schema Validation via Newtonsoft.Json.Schema validate VALUES? - c#

I have a small sample. If my Json is good, it works correctly. If I change the "tag" (aka, the property name), it works correctly by having invalid messages. If I change the value of a Guid to be a non-guid-value, the Json Schema Validation does not fail.
Is there a way to fail validation for a Guid value?
public class MyCoolObject
{
public Guid TheUuid { get; set; }
public Int32 TheInteger { get; set; }
public DateTime TheDateTime { get; set; }
}
and my test method. When i = 2 (and I'm setting the string to contain "NOTAGUID-3333-3333-3333-333333333333"), that is when I don't get error messages like I would like to.
private static void RunJsonSchemaValidate()
{
/* Note, the TheUuid is of type "string" and format "guid" */
string jsonSchemaText = #"
{
""typeName"": ""MyCoolObject"",
""additionalProperties"": false,
""type"": ""object"",
""required"": [
""TheUuid"",
""TheInteger"",
""TheDateTime""
],
""properties"": {
""TheUuid"": {
""type"": ""string"",
""format"": ""guid""
},
""TheInteger"": {
""type"": ""integer""
},
""TheDateTime"": {
""type"": ""string"",
""format"": ""date-time""
}
},
""$schema"": ""http://json-schema.org/draft-04/schema#""
}
";
Newtonsoft.Json.Schema.JSchema jschem = Newtonsoft.Json.Schema.JSchema.Parse(jsonSchemaText);
for (int i = 0; i < 3; i++)
{
string jsonContent = string.Empty;
switch (i)
{
case 1:
/* bad json, change the property NAME */
jsonContent = #"{
""TheUuidXXX"": ""33333333-3333-3333-3333-333333333333"",
""TheInteger"": 2147483647,
""TheDateTime"": ""2017-08-22T15:32:10.7023008-04:00""
}";
break;
case 2:
/* bad json, change the property VALUE */
jsonContent = #"{
""TheUuid"": ""NOTAGUID-3333-3333-3333-333333333333"",
""TheInteger"": 2147483647,
""TheDateTime"": ""2017-08-22T15:32:10.7023008-04:00""
}";
break;
case 3:
/* bad json, bad integer */
jsonContent = #"{
""TheUuid"": ""33333333-3333-3333-3333-333333333333"",
""TheInteger"": notAnumber,
""TheDateTime"": ""2017-08-22T15:32:10.7023008-04:00""
}";
break;
case 4:
/* bad json, bad date */
jsonContent = #"{
""TheUuid"": ""33333333-3333-3333-3333-333333333333"",
""TheInteger"": 2147483647,
""TheDateTime"": ""NOTADATE""
}";
break;
default:
/* good json */
jsonContent = #"{
""TheUuid"": ""33333333-3333-3333-3333-333333333333"",
""TheInteger"": 2147483647,
""TheDateTime"": ""2017-08-22T15:32:10.7023008-04:00""
}";
break;
}
/* START THE MEAT OF THIS PROCEDURE */
Newtonsoft.Json.Linq.JObject jobj = Newtonsoft.Json.Linq.JObject.Parse(jsonContent);
IList<string> messages;
bool valid = jobj.IsValid(jschem, out messages);
/* ENDTHE MEAT OF THIS PROCEDURE */
if (!valid)
{
string errorMsg = "i=" + i.ToString() + ":" + string.Join(",", messages);
Console.WriteLine(string.Empty);
Console.WriteLine(string.Empty);
Console.WriteLine(errorMsg);
}
else
{
Console.WriteLine(string.Empty);
Console.WriteLine(string.Empty);
Console.WriteLine("i=" + i.ToString() + ":" + "Good json Yes");
MyCoolObject thisShouldWorkWhenValidationPasses = Newtonsoft.Json.JsonConvert.DeserializeObject<MyCoolObject>(jsonContent);
}
Console.WriteLine(string.Empty);
Console.WriteLine("--------------------------------------------------");
Console.WriteLine(string.Empty);
}
and the packages
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="Newtonsoft.Json" version="10.0.2" targetFramework="net45" />
<package id="Newtonsoft.Json.Schema" version="3.0.3" targetFramework="net45" />
</packages>
So what is happening is that when i=2, the json-schema passes, but then MyCoolObject thisShouldWorkWhenValidationPasses throws an exception....
i=2:Good json Yes
Unhandled Exception: Newtonsoft.Json.JsonSerializationException: Error
converting value "NOTAGUID-3333-3333-3333-333333333333" to type
'System.Guid'. Path 'TheUuid', line 2, position 77. --->
System.ArgumentException: Could not cast or convert from System.String
to System.Guid.
:(
I'm trying to have the json-schema fail earlier.
The end-game is to perform a json-schema-validation without exceptions getting thrown. Then after "everything is clear" try to load the objects. My real stuff is more complex, but this small demo shows the issue(s).
I also replaced the "meat of this procedure" with the below code
/* START THE MEAT OF THIS PROCEDURE */
Newtonsoft.Json.JsonTextReader reader = new Newtonsoft.Json.JsonTextReader(new System.IO.StringReader(jsonContent));
Newtonsoft.Json.Schema.JSchemaValidatingReader validatingReader = new Newtonsoft.Json.Schema.JSchemaValidatingReader(reader);
validatingReader.Schema = JSchema.Parse(schemaJson);
IList<string> messages = new List<string>();
validatingReader.ValidationEventHandler += (o, a) => messages.Add(a.Message);
Newtonsoft.Json.JsonSerializer serializer = new Newtonsoft.Json.JsonSerializer();
/* below is the issue with this code..you still try to serialize the object...and that can throw an exception */
MyCoolObject p = serializer.Deserialize<MyCoolObject>(validatingReader);
bool valid = !messages.Any();
/* END THE MEAT OF THIS PROCEDURE */
But again, this is subject to exceptions being thrown .. trying to validate.

Thanks to Jeroen Mostert for the hint that led me to this solution:
/* START THE MEAT OF THIS PROCEDURE */
IList<string> deserializeMessages = new List<string>();
/* first get any serialization issues */
MyCoolObject p = JsonConvert.DeserializeObject<MyCoolObject>(jsonContent,
new JsonSerializerSettings
{
Error = delegate (object sender, Newtonsoft.Json.Serialization.ErrorEventArgs args)
{
deserializeMessages.Add(args.ErrorContext.Error.Message);
args.ErrorContext.Handled = true;
}
});
IList<string> jsonSchemaMessages = new List<string>();
bool jsonSchemaIsValid = true;
/* now, only if there were no serialization issues, look at the schema */
if (!deserializeMessages.Any())
{
Newtonsoft.Json.Linq.JObject jobj = Newtonsoft.Json.Linq.JObject.Parse(jsonContent);
jsonSchemaIsValid = jobj.IsValid(jschem, out jsonSchemaMessages);
}
IEnumerable<string> allMessages = deserializeMessages.Union(jsonSchemaMessages);
bool overallValid = !allMessages.Any();
/* END THE MEAT OF THIS PROCEDURE */
This gives me the desired output for this situation:
i=0:Good json Yes
i=1:Property 'TheUuidXXX' has not been defined and the schema does not
allow additional properties. Path 'TheUuidXXX', line 2, position
41.,Required properties are missing from object: TheUuid. Path '', line 1, position 1.
i=2:Error converting value "NOTAGUID-3333-3333-3333-333333333333" to
type 'System.Guid'. Path 'TheUuid', line 2, position 77.
i=3:Unexpected character encountered while parsing value: o. Path
'TheInteger', line 3, position 41.,Error parsing boolean value. Path
'TheInteger', line 3, position 42.
i=4:Could not convert string to DateTime: NOTADATE. Path
'TheDateTime', line 4, position 50.
PRESS ENTER TO EXIT
I'm still wrapping my head around it a little. But in my specific situation (where I want to Response back to the http request immediately there was a json issue), it works.
I won't mark this as "the answer" in case anyone comes up with something better.
Note, I changed my i for loop to be < 5
for (int i = 0; i < 5; i++)

Related

C# equivalent of Java org.json.JSONObject

I'm trying to convert a java project to C#. In the following piece I don't know how to convert the Json part.
Cursor resultSet = helper.openDataBase().rawQuery("Select * from word where wname=?", new String[] {String.valueOf(editable)});
TextView TextView_FA = findViewById(R.id.textView_FA);
if( resultSet.moveToFirst())
{
String str_json = resultSet.getString(2);
try {
JSONObject obj = new JSONObject(str_json);
String trans = obj.getJSONArray("ss").optJSONObject(0) .getString("s");
TextView_FA.setText(trans);
} catch (JSONException e) {
TextView_FA.setText(e.getLocalizedMessage());
}
}
else {
TextView_FA.setText("no translation found");
}
This is what I've tried:
EditText EditText_en = FindViewById<EditText>(Resource.Id.EditText_en);
Java.IO.File fil = new Java.IO.File(db_src);
SQLiteDatabase db = SQLiteDatabase.OpenDatabase(fil,null);
Android.Database.ICursor resultSet = db.RawQuery("Select * from word where wname =? ",new[]{ EditText_en.Text});
TextView TextView_FA = FindViewById<TextView>(Resource.Id.TextView_fa);
if (resultSet.MoveToFirst())
{
String str_json = resultSet.GetString(2);
try
{
// JSONObject obj = new JSONObject(str_json);
// String trans = obj.getJSONArray("ss").optJSONObject(0).getString("s");
TextView_FA.Text = trans;
}
catch (Exception e)
{
TextView_FA.Text = e.Message;
}
}
else
{
TextView_FA.Text = "no translation found" ;
}
The two line I've commented is the question.
I tried to use System.Text.Json or System.Json as some of the internet docs has said but VS2019
intellisense doesn't recognize them as a valid library.
To use the NewtonSoft.JSon i probably the most common way to Deserialize json and a bit easier (forgiving) than the System.Text.Json. It is also easier to work with JSon if you have a known type. I don't know how your JSon sttring look like but I have made my own example string
//[
// {
// color: "red",
// value: "#f00"
// },
// {
// color: "green",
// value: "#0f0"
// },
// {
// color: "blue",
// value: "#00f"
// }
//]
string myJson = "[\r\n\t{\r\n\t\t\"color\": \"red\",\r\n\t\t\"value\": \"#f00\"\r\n\t},\r\n\t{\r\n\t\t\"color\": \"green\",\r\n\t\t\"value\": \"#0f0\"\r\n\t},\r\n\t{\r\n\t\t\"color\": \"blue\",\r\n\t\t\"value\": \"#00f\"\r\n\t}\r\n\t\r\n]";
If you have a class or can define it, it will be easier to work with the JSon, but I have created an example without use of the class to
public class custColor
{
public string color { get; set; }
public string value { get; set; }
}
Examples with both NewtonSoft and System.Text.Json
//NewtonSoft JSON
var arrayOfColors = JsonConvert.DeserializeObject<custColor[]>(myJson);
var valueFromArray = arrayOfColors[0].value; //Will give #f00
var dynamicColorArray = JsonConvert.DeserializeObject<dynamic>(myJson);
var valueFromDynArray = dynamicColorArray[0].value; //Will also give #f00
//System.Text.Json
var stjArrayOfColors = System.Text.Json.JsonSerializer.Deserialize<custColor[]>(myJson);
var stjValueFromArray = stjArrayOfColors[0].value; //Will give #f00

How to Get index of a Character in an Unknown Line of a Multiline string in c#

I'm trying to get covid-19 results (only information about Iran) from an Api and show it on a textbox.
and the full result (all countries) that i get from the Api is a json format.
so to get only Iran section i made a Function that loops through lines of the string one by one and check if in that line there is a "{" and if yes get index of that and continue checking if in another line there is a "}" and get index of that too then check if between these, there is "Iran" then add this text (from "{" to "}") in a string:
private string getBetween(string strSourceText, string strStartingPosition, string strEndingPosition)
{
int Starting_CurlyBracket_Index = 0;
int Ending_CurlyBracket_Index = 0;
string FinalText = null;
bool isTurnTo_firstIf = true;
foreach (var line in strSourceText.Split('\r', '\n'))
{
if (isTurnTo_firstIf == true)
{
if (line.Contains(strStartingPosition))
{
Starting_CurlyBracket_Index = line.IndexOf(strStartingPosition); //i think problem is here
isTurnTo_firstIf = false;
}
}
else if (isTurnTo_firstIf == false)
{
if (line.Contains(strEndingPosition))
{
Ending_CurlyBracket_Index = line.IndexOf(strEndingPosition); //i think problem is here
if (strSourceText.Substring(Starting_CurlyBracket_Index, Ending_CurlyBracket_Index - Starting_CurlyBracket_Index).Contains("Iran")) //error here
{
FinalText = strSourceText.Substring(Starting_CurlyBracket_Index, Ending_CurlyBracket_Index - Starting_CurlyBracket_Index);
break;
}
else
{
isTurnTo_firstIf = true;
}
}
}
}
return FinalText;
}
and i call the function like this:
string OnlyIranSection = getBetween(Sorted_Covid19_Result, "{", "}"); //Sorted_Covid19_Result is the full result in json format that converted to string
textBox1.Text = OnlyIranSection;
but i get this Error:
and i know.. its because it gets indexes in the current line but what i need is getting that index in the strSourceText so i can show only this section of the whole result:
USING JSON
As per the comments I read it was really needed to use JSON utility to achieve your needs easier.
You can start with this basic example:
static void Main(string[] args)
{
string jsonString = #"{
""results"": [
{""continent"":""Asia"",""country"":""Indonesia""},
{""continent"":""Asia"",""country"":""Iran""},
{""continent"":""Asia"",""country"":""Philippines""}
]
}";
var result = JsonConvert.DeserializeObject<JsonResult>(jsonString);
var iranInfo = result.InfoList.Where(i => i.Country.ToString() == "Iran").FirstOrDefault();
}
public class JsonResult
{
[JsonProperty("results")]
public List<Info> InfoList { get; set; }
}
public class Info
{
public object Continent { get; set; }
public object Country { get; set; }
}
UPDATE: USING INDEX
As long as the structure of the JSON is consistent always then this kind of sample solution can give you hint.
Console.WriteLine("Original JSON:");
Console.WriteLine(jsonString);
Console.WriteLine();
Console.WriteLine("Step1: Make the json as single line,");
jsonString = jsonString.Replace(" ", "").Replace(Environment.NewLine, " ");
Console.WriteLine(jsonString);
Console.WriteLine();
Console.WriteLine("Step2: Get index of country Iran. And use that index to get the below output using substring.");
var iranIndex = jsonString.ToLower().IndexOf(#"""country"":""iran""");
var iranInitialInfo = jsonString.Substring(iranIndex);
Console.WriteLine(iranInitialInfo);
Console.WriteLine();
Console.WriteLine("Step3: Get inedx of continent. And use that index to get below output using substring.");
var continentIndex = iranInitialInfo.IndexOf(#"""continent"":");
iranInitialInfo = iranInitialInfo.Substring(0, continentIndex-3);
Console.WriteLine(iranInitialInfo);
Console.WriteLine();
Console.WriteLine("Step4: Get the first part of the info by using. And combine it with the initialInfo to bring the output below.");
var beginningIranInfo = jsonString.Substring(0, iranIndex);
var lastOpenCurlyBraceIndex = beginningIranInfo.LastIndexOf("{");
beginningIranInfo = beginningIranInfo.Substring(lastOpenCurlyBraceIndex);
var iranInfo = beginningIranInfo + iranInitialInfo;
Console.WriteLine(iranInfo);
OUTPUT USING INDEX:

SimpleJSON Unity Exception: Error deserializing JSON. Unknown tag: 123

I'm Getting this error when accessing data from a json file.
I'm trying to follow the following tutorial: http://wiki.unity3d.com/index.php/SimpleJSON
and created a test.json file, that I want to extract data from containing:
{
"version": "1.0",
"data": {
"sampleArray": [
"string value",
5,
{
"name": "sub object"
}
]
}
}
using the following code in Unity:
void LoadFiles()
{
FileInfo f = m_info[0]; //Array of Files in Folder
// I had a foreach loop here, but wanted to specify the file for testing before I tried to parse through one of my own
print("I Found : " + f);
var N = JSONNode.LoadFromFile(f.FullName);
var versionString = N["version"].Value; // versionString will be a string containing "1.0"
var versionNumber = N["version"].AsFloat; // versionNumber will be a float containing 1.0
var name = N["data"]["sampleArray"][2]["name"];// name will be a string containing "sub object"
print("vs=" + versionString + " vn=" + versionNumber + " name=" + name);
}
and all i get is Unknown tags, from what I gather from the source :
public static JSONNode Deserialize(System.IO.BinaryReader aReader)
{
JSONBinaryTag type = (JSONBinaryTag)aReader.ReadByte();
switch(type)
{
case JSONBinaryTag.Array:
{
int count = aReader.ReadInt32();
JSONArray tmp = new JSONArray();
for(int i = 0; i < count; i++)
tmp.Add(Deserialize(aReader));
return tmp;
}
case JSONBinaryTag.Class:
{
int count = aReader.ReadInt32();
JSONClass tmp = new JSONClass();
for(int i = 0; i < count; i++)
{
string key = aReader.ReadString();
var val = Deserialize(aReader);
tmp.Add(key, val);
}
return tmp;
}
case JSONBinaryTag.Value:
{
return new JSONData(aReader.ReadString());
}
case JSONBinaryTag.IntValue:
{
return new JSONData(aReader.ReadInt32());
}
case JSONBinaryTag.DoubleValue:
{
return new JSONData(aReader.ReadDouble());
}
case JSONBinaryTag.BoolValue:
{
return new JSONData(aReader.ReadBoolean());
}
case JSONBinaryTag.FloatValue:
{
return new JSONData(aReader.ReadSingle());
}
default:
{
throw new Exception("Error deserializing JSON. Unknown tag: " + type);
}
}
}
I'm falling all the way through the Switch, but with .Value or .AsFloat I should hit those case statements. Any Idea what's going on, is this code to old for Unity 5.0 ?
It seems like I was under false pretenses, that the JSON file was like XML, text, well it seems it is not, or at least assumed to be binary by SimpleJson when reading files. I tried writing the "Text" to a file, and then reading it and it worked fine. So this is an error where I assumed the data in the examples to be text.
JSONNode.LoadFromFile function instead to JSONNode.Parse(string) convert stream to string
System.IO.FileStream fs = System.IO.File.OpenRead(f.FullName);
long length = fs.Length;
byte[] stream = new byte[length];
fs.Read(stream, 0, (int)length);
string json = System.Text.Encoding.UTF8.GetString(stream);
var N = JSONNode.Parse(json);

Detect language of string from Google API C#

i am trying to detect what language the written txt of player.LastChat is, and i am having some difficulties.
Here's the code i have:
String[] words = player.LastChat.Trim().Split(new Char[]{' ','\t',',','.',':','!','?',';','(',')',']','[','"'});
StringBuilder edited = new StringBuilder();
// Remove exception list words from line
foreach (String w in words) {
if (plugin.isInList(w, "good_words")) {
continue;
}
edited.Append(w);
edited.Append(" ");
}
// URL Encode edited string
String UnreservedChars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_.~";
StringBuilder Result = new StringBuilder();
String Input = edited.ToString();
for (int x = 0; x < Input.Length; ++x)
{
if (UnreservedChars.IndexOf(Input[x]) != -1)
Result.Append(Input[x]);
else
Result.Append("%").Append(String.Format("{0:X2}", (int)Input[x]));
}
String key = "API KEY";
// Test for badness
bool jsonresult = false;
try {
WebClient client = new WebClient();
String json = client.DownloadString("https://www.googleapis.com/language/translate/v2/detect?key=" + key + "&q=" + Result.ToString());
jsonresult = json.Contains("en");
} catch (Exception e) {
plugin.ConsoleWrite("Language check failed! Error: " + e);
}
if (!jsonresult) {
return true;
}
plugin.ConsoleWrite("Language: " + jsonresult);
return jsonresult; // for Actions
So, what i am trying to achieve, is to return true if it is any other language than "en" (english), but it is returning true no matter what.
The response from google is this:
{
"data": {
"detections": [
[
{
"language": "en",
"isReliable": false,
"confidence": 0.03396887
}
]
]
}
}
Any help is much appreciated, and i have no idea how to code, this code is borrowed from another script.
Regards.
To make method work as described, you should change:
if (!jsonresult) {
return true;
}
plugin.ConsoleWrite("Language: " + jsonresult);
return jsonresult;
to:
plugin.ConsoleWrite("Language: " + jsonresult);
return !jsonresult;
also this line
jsonresult = json.Contains("en");
is checking for any occurance of "en" in json text (and is found in "confidence" in your json). What you should do, is to parse Json using json.net (or other lib), or simply do this (but is an ugly hack):
jsonresult = json.Contains("\"language\": \"en\",");

Json : Unexpected character encountered while parsing value: s. Path '', line 0, position 0

This Code;
public void ProcessRequest(HttpContext context)
{
string jSon = new StreamReader(context.Request.InputStream).ReadToEnd();
string result = LETSGO.BUSINESS.Process.ApiProcesRequest(jSon);
context.Response.ContentType = "application/json";
context.Response.Write(result);
}
Error : Unexpected character encountered while parsing value: s. Path '', line 0, position 0.
How do I fix error ?
This function send;
public static string ApiProcesRequest(string request)
{
Result result = new Result();
try
{
var req = JsonConvert.DeserializeObject<Request>(request);
switch (req.RequestType)
{
#region 1002 - Kullanıcı şifre hatırlatma
case "1002":
result = UserProcess.PasswordReminder(request);
return JsonConvert.SerializeObject(result);
break;
#endregion } } }
string jSon = new StreamReader(context.Request.InputStream).ReadToEnd();
Here you might got the string like s.Path, it can not be deserialize due to it's not a well-formed json object.

Categories

Resources