My json file is mostly an array that contain objects but the list is incomplete, so I can't use the last entry. I would like to deserialize the rest of the file while discarding the last invalid entry
[ { "key" : "value1" }, { "key " : "value2"}, { "key
Please tell me if there is a way using Newtonsoft.Json library, or do I need some preprocessing.
Thank you!
Looks like on Json.NET 8.0.3 you can stream your string from a JsonTextReader to a JTokenWriter and get a partial result by catching and swallowing the JsonReaderException that gets thrown when parsing the truncated JSON:
JToken root;
string exceptionPath = null;
using (var textReader = new StringReader(badJson))
using (var jsonReader = new JsonTextReader(textReader))
using (JTokenWriter jsonWriter = new JTokenWriter())
{
try
{
jsonWriter.WriteToken(jsonReader);
}
catch (JsonReaderException ex)
{
exceptionPath = ex.Path;
Debug.WriteLine(ex);
}
root = jsonWriter.Token;
}
Console.WriteLine(root);
if (exceptionPath != null)
{
Console.WriteLine("Error occurred with token: ");
var badToken = root.SelectToken(exceptionPath);
Console.WriteLine(badToken);
}
This results in:
[
{
"key": "value1"
},
{
"key ": "value2"
},
{}
]
You could then finish deserializing the partial object with JToken.ToObject. You could also delete the incomplete array entry by using badToken.Remove().
It would be better practice not to generate invalid JSON in the first place though. I'm also not entirely sure this is documented functionality of Json.NET, and thus it might not work with future versions of Json.NET. (E.g. conceivably Newtonsoft could change their algorithm such that JTokenWriter.Token is only set when writing is successful.)
You can use the JsonReader class and try to parse as far as you get. Something like the code below will parse as many properties as it gets and then throw an exception. This is of course if you want to deserialize into a concrete class.
public Partial FromJson(JsonReader reader)
{
while (reader.Read())
{
// Break on EndObject
if (reader.TokenType == JsonToken.EndObject)
break;
// Only look for properties
if (reader.TokenType != JsonToken.PropertyName)
continue;
switch ((string) reader.Value)
{
case "Id":
reader.Read();
Id = Convert.ToInt16(reader.Value);
break;
case "Name":
reader.Read();
Name = Convert.ToString(reader.Value);
break;
}
}
return this;
}
Code taken from the CGbR JSON Target.
the second answer above is really good and simple, helped me out!
static string FixPartialJson(string badJson)
{
JToken root;
string exceptionPath = null;
using (var textReader = new StringReader(badJson))
using (var jsonReader = new JsonTextReader(textReader))
using (JTokenWriter jsonWriter = new JTokenWriter())
{
try
{
jsonWriter.WriteToken(jsonReader);
}
catch (JsonReaderException ex)
{
exceptionPath = ex.Path;
}
root = jsonWriter.Token;
}
return root.ToString();
}
Related
i using jaray for reading json file
there is my c# code
Console.Write("enter database name:");
string dbname = Console.ReadLine();
string workingDirectory = Environment.CurrentDirectory;
string dbdirectory = Directory.GetParent(workingDirectory).Parent.Parent.FullName;
//string en_dbsdatas = File.ReadAllText(dbdirectory + #"\jsondb\dbsdatas.json");
string en_dbsdatas = File.ReadAllText(dbdirectory + #"\jsondb\dbsdatas.json");
JArray de_jArray = JArray.Parse(en_dbsdatas);
bool flag = true;
foreach (JObject i in de_jArray)
{
if ((string)i["dbname"] == dbname)
{
Directory.Delete((string)i["dbpath"]);
flag = true;
break;
}
else
{
flag = false;
}
}
and there is my json file (dbsdatas.json)
{
"datas": [
{
"dbname": "mydb",
"dbpath": "c:\\projects\\mydb"
},
{
"dbname": "ssmydb",
"dbpath": "c:\\prssojects\\mydb"
}
]
}
i catch an exeption in runnig program.
my exeption is 'Error reading JArray from JsonReader. Current JsonReader item is not an array' in line JArray de_jArray = JArray.Parse(en_dbsdatas);
whrere is the problem?
i catch an exeption in runnig program.
your syntax is wrong, you can use
var de_jObject = JObject.Parse(en_dbsdatas);
or
JArray de_jArray = (JArray)JObject.Parse(en_dbsdatas)["datas"];
Your json is json object, not a json array. Data property inside of json is a json array
My json file is mostly an array that contain objects but the list is incomplete, so I can't use the last entry. I would like to deserialize the rest of the file while discarding the last invalid entry
[ { "key" : "value1" }, { "key " : "value2"}, { "key
Please tell me if there is a way using Newtonsoft.Json library, or do I need some preprocessing.
Thank you!
Looks like on Json.NET 8.0.3 you can stream your string from a JsonTextReader to a JTokenWriter and get a partial result by catching and swallowing the JsonReaderException that gets thrown when parsing the truncated JSON:
JToken root;
string exceptionPath = null;
using (var textReader = new StringReader(badJson))
using (var jsonReader = new JsonTextReader(textReader))
using (JTokenWriter jsonWriter = new JTokenWriter())
{
try
{
jsonWriter.WriteToken(jsonReader);
}
catch (JsonReaderException ex)
{
exceptionPath = ex.Path;
Debug.WriteLine(ex);
}
root = jsonWriter.Token;
}
Console.WriteLine(root);
if (exceptionPath != null)
{
Console.WriteLine("Error occurred with token: ");
var badToken = root.SelectToken(exceptionPath);
Console.WriteLine(badToken);
}
This results in:
[
{
"key": "value1"
},
{
"key ": "value2"
},
{}
]
You could then finish deserializing the partial object with JToken.ToObject. You could also delete the incomplete array entry by using badToken.Remove().
It would be better practice not to generate invalid JSON in the first place though. I'm also not entirely sure this is documented functionality of Json.NET, and thus it might not work with future versions of Json.NET. (E.g. conceivably Newtonsoft could change their algorithm such that JTokenWriter.Token is only set when writing is successful.)
You can use the JsonReader class and try to parse as far as you get. Something like the code below will parse as many properties as it gets and then throw an exception. This is of course if you want to deserialize into a concrete class.
public Partial FromJson(JsonReader reader)
{
while (reader.Read())
{
// Break on EndObject
if (reader.TokenType == JsonToken.EndObject)
break;
// Only look for properties
if (reader.TokenType != JsonToken.PropertyName)
continue;
switch ((string) reader.Value)
{
case "Id":
reader.Read();
Id = Convert.ToInt16(reader.Value);
break;
case "Name":
reader.Read();
Name = Convert.ToString(reader.Value);
break;
}
}
return this;
}
Code taken from the CGbR JSON Target.
the second answer above is really good and simple, helped me out!
static string FixPartialJson(string badJson)
{
JToken root;
string exceptionPath = null;
using (var textReader = new StringReader(badJson))
using (var jsonReader = new JsonTextReader(textReader))
using (JTokenWriter jsonWriter = new JTokenWriter())
{
try
{
jsonWriter.WriteToken(jsonReader);
}
catch (JsonReaderException ex)
{
exceptionPath = ex.Path;
}
root = jsonWriter.Token;
}
return root.ToString();
}
I have a ASP MVC project with some Ajax Calls, where I am trying to pass from jquery/Ajax to my AjaxController (see bellow code) where in the controller sting item is receiving a json string like this
"[\n \"1002\",\n \"1003\"\n]"
And I get this error in my controller (See bellow code where the comment identifies the error)
Newtonsoft.Json.JsonSerializationException: Error converting value "1002" to type 'System.String[]'. Path '[0]', line 2, position 9. ---> System.ArgumentException: Could not cast or convert from System.String to System.String[]. at Newtonsoft.Json.Utilities.ConvertUtils.EnsureTypeAssignable(Object value, Type initialType, Type targetType) at Newtonsoft.Json.Utilities.ConvertUtils.ConvertOrCast(Object initialValue, CultureInfo culture, Type targetType) at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.EnsureType(JsonReader reader, Object value, CultureInfo culture, JsonContract contract, Type targetType) ...(continue)
This is my Json/Jquery creation function
function SaveObservations() {
var SerSel = $("#ServiceIdSelect2").val();
var obs = $("#observation").val();
var itemsX = [];
if (obs == "") {
mostrar_alert_ui("Validation message", "Observation cannot be null", 350);
} else {
//Start json creation
$("#ItemsPieces > input:checked").each(function () {
var id = $(this).val();
itemsX.push(id);
});
var itemsY = JSON.stringify(itemsX, null, 2);
//End json creation
Funciones_Ajax_conAlert("/Ajax/SendEmailItemsToClient/", { proyecto: SerSel, items: itemsY, observation: obs }, CloseObservations);
}
}
And here is my controller where the error is given
public JsonResult SendEmailItemsToClient(int proyecto, string items, string observation)
{
object data = null;
try
{
List<string[]> datax1 = JsonConvert.DeserializeObject<List<string[]>>(items); //Here is the issue Aqui tengo el problema
foreach (var item in datax1)
{
string test = item.ToString();
}
string mensaje = "";
int ProjectIdx = proyecto;
bool resp = CorreccionesController.SendItemsDifferentsToClient(ProjectIdx, mensaje);
if (resp) {
data = new
{
success = true,
titulo = "Notification",
mensaje = "A message explaining why the different items selected are used had been sent"
};
}
else
{
data = new
{
success = false,
titulo = "Notification",
mensaje = "The observation is Saved but the email couldn't be send, please contact support"
};
}
}
catch (Exception ex)
{
data = new
{
success = false,
titulo = "ERROR",
mensaje = ex.ToString()
};
}
return Json(data, JsonRequestBehavior.AllowGet);
}
The question would be how can I itterate that json string without receiving an error?
Your code need a little bit of refactoring; basically you have a json structure like this one:
[
"1002",
"1003"
]
That is basically an Array of Strings.
In your Controller you have the following line:
List<string[]> datax1 = JsonConvert.DeserializeObject<List<string[]>>(items);
Now, what this little chunk of code List<string[]> means? With that line you are trying to create a List of arrays of string, something like this:
[
["1002","1003"],
["1002","1003"]
]
So your deserializing methods fails with the following message: Could not cast or convert from System.String to System.String[]. Now makes sense.
So if you want to deserialize an json array of string you just needs:
List<string> datax1 = JsonConvert.DeserializeObject<List<string>>(items);
List<string> is just like and array of string(internally a list is constructed on an array basis, check this answer for more information about array and list: Array versus List<T>: When to use which?
Based on that info you can write your code this way too:
string[] datax1 = JsonConvert.DeserializeObject<string[]>(items); //Not tested, but should works.
Don't double Json encode, and let the WebAPI do all the work:
function SaveObservations() {
var SerSel = $("#ServiceIdSelect2").val();
var obs = $("#observation").val();
var itemsX = [];
if (obs == "") {
mostrar_alert_ui("Validation message", "Observation cannot be null", 350);
} else {
//Start json creation
$("#ItemsPieces > input:checked").each(function () {
var id = $(this).val();
itemsX.push(id);
});
//End json creation
Funciones_Ajax_conAlert("/Ajax/SendEmailItemsToClient/", { proyecto: SerSel, items: itemsX, observation: obs }, CloseObservations);
}
}
and
public JsonResult SendEmailItemsToClient(int proyecto, string[] items, string observation)
{
object data = null;
try
{
foreach (var item in items)
{
string test = item.ToString();
}
string mensaje = "";
int ProjectIdx = proyecto;
bool resp = CorreccionesController.SendItemsDifferentsToClient(ProjectIdx, mensaje);
if (resp) {
data = new
{
success = true,
titulo = "Notification",
mensaje = "A message explaining why the different items selected are used had been sent"
};
}
else
{
data = new
{
success = false,
titulo = "Notification",
mensaje = "The observation is Saved but the email couldn't be send, please contact support"
};
}
}
catch (Exception ex)
{
data = new
{
success = false,
titulo = "ERROR",
mensaje = ex.ToString()
};
}
return Json(data, JsonRequestBehavior.AllowGet);
}
I have some code that looks like this:
public Tuple<bool, SomeObjectModel> CheckIfJsonIsValid(string IncomingJson)
{
SomeObjectModel TheObjectModel = new SomeObjectModel();
JavascriptSerializer TheSerializer = new JavascriptSerializer();
.....
try
{
TheObjectModel = TheSerializer.Deserialize<SomeObjectModel>(IncomingJson);
}
catch
{
return new Tuple<bool, SomeObjectModel>(false, null); //question here
}
.....
return new Tuple<bool, SomeObjectModel>(true, TheObjectModel);
}
The calling method first check the returning tuple's Item1, and if it's false, ends its process.
Is it better practice a) to return a null value in the Tuple or b) to return a new and fresh instance of SomeObjectModel? Are there any performance implications?
Thanks for your suggestions.
Let me suggest three alternative solutions:
ParseJsonIfValid: If deserializing works, TheObjectModel is always non-null. Thus, there is no need for the boolean:
public SomeObjectModel ParseJsonIfValid(string IncomingJson)
{
JavascriptSerializer TheSerializer = new JavascriptSerializer();
.....
try
{
return TheSerializer.Deserialize<SomeObjectModel>(IncomingJson);
}
catch
{
return null;
}
}
In the calling function simply check whether the return value is null or not.
ParseJson: If the JSON is usually valid, and invalid JSON is a sign of something gone terribly wrong, just throw an exception:
public SomeObjectModel ParseJson(string IncomingJson)
{
JavascriptSerializer TheSerializer = new JavascriptSerializer();
.....
try
{
return TheSerializer.Deserialize<SomeObjectModel>(IncomingJson);
}
catch (Exception e)
{
throw new TheServerSentRubbishException(e);
}
}
Be sure to include the inner ("real") exception, so that the calling function can log the real cause of the error for debugging purposes.
TryParseJson: If null can be a valid deserialization, you can use the following pattern, which has the advantage of being consistent with the TryParse methods of the .NET framework:
public bool TryParseJson(string IncomingJson, out SomeObjectModel theObjectModel)
{
JavascriptSerializer TheSerializer = new JavascriptSerializer();
.....
try
{
theObjectModel = TheSerializer.Deserialize<SomeObjectModel>(IncomingJson);
return true;
}
catch (Exception e)
{
return false;
}
}
I created a homescreen widget, that gets a table of strings from a website. Instead of getting data from web on every update, I want to save the table to the phone and than read from the file on update. I'm using Mono for Android (C#).
Here is a method for saving data to the file system using XML Serialization
public static bool SaveData<T>(Context context, string fileName, T data)
{
try
{
using (Stream stream = context.OpenFileOutput(fileName, FileCreationMode.Private))
{
XmlSerializer xmlSerializer = new XmlSerializer(typeof(T));
xmlSerializer.Serialize(stream, data);
}
return true;
}
catch (Exception)
{
return false;
}
}
And here is a method for loading serialized data from the file system
public static T LoadData<T>(Context context, string fileName)
{
Java.IO.File file = context.GetFileStreamPath(fileName);
if (file.Exists())
{
using (Stream openStream = context.OpenFileInput(fileName))
{
using (StreamReader reader = new StreamReader(openStream))
{
try
{
XmlSerializer serializer = new XmlSerializer(typeof(T));
var loadedObject = serializer.Deserialize(reader);
return (T)loadedObject;
}
catch (Exception ex)
{
// TODO Handle error
return default(T);
}
}
}
}
else
{
throw new Java.IO.FileNotFoundException("Could not find file " + fileName);
}
}
Using these methods you can easily save and load any serializable object such as a string[] you retrieved from the website.
string[] data = { "one", "two", "three" };
JavaIO.SaveData(this, "SavedData.txt", data);
string[] loadedData = JavaIO.LoadData<string[]>(this, "SavedData.txt");
If it's just a simple list, then you can use System.IO.File to load/save text - and you can use something like JSON.Net to convert your list to/from text.
If your data is more incremental, then you can use SQLite instead - try the the SQLite-net ORM wrapper on GitHub