I'm not sure if I'm double-serializing my JSON object, but the output results in an unwanted format. I'm exposing the REST endpoint via an ArcGIS Server Object Extension (REST SOE). I've also recently implemented JSON.Net which essentially allowed me to remove several lines of code.
So here is the handler, which is the core piece creating the data for the service (for you non GIS peeps).
private byte[] SearchOptionsResHandler(NameValueCollection boundVariables, string outputFormat, string requestProperties, out string responseProperties)
{
responseProperties = null;
JsonObject result = new JsonObject();
// Towns
DataTable dataTableTowns = GetDataTableTowns();
String jsonStringTowns = JsonConvert.SerializeObject(dataTableTowns);
result.AddString("Towns", jsonStringTowns);
// GL_Description
DataTable dataTableGLDesc = GetDataTableGLDesc();
String jsonStringGLDesc = JsonConvert.SerializeObject(dataTableGLDesc);
result.AddString("GLDesc", jsonStringGLDesc);
return Encoding.UTF8.GetBytes(result.ToJson());
}
The result is ugly scaped JSON:
{
"Towns": "[{\"Column1\":\"ANSONIA\"},{\"Column1\":\"BETHANY\"},{\"Column1\":\"BLOOMFIELD\"}]",
"GLDesc": "[{\"Column1\":\"Commercial\"},{\"Column1\":\"Industrial\"},{\"Column1\":\"Public\"}]"
}
Is it because I'm double serializing it somehow? Thanks for looking this over.
Yes, you are double serializing it. It's right there in your code.
For each of your data tables, dataTableTowns and dataTableGLDesc, you are calling JsonConvert.SerializeObject() to convert them to JSON strings, which you then add to a result JsonObject. You then call ToJson() on the result, which presumably serializes the whole thing to JSON again.
JsonObject is not part of Json.Net, while JsonConvert is, so I would recommend using one or the other. Generally, you just want to accumulate everything into a single result object and then serialize the whole thing once at the end. Here is how I would do it with Json.Net using an anonymous object to hold the result:
var result = new
{
Towns = GetDataTableTowns(),
GLDesc = GetDataTableGLDesc()
};
string json = JsonConvert.SerializeObject(result);
return Encoding.UTF8.GetBytes(json);
Here is the output:
{
"Towns":[{"Column1":"ANSONIA"},{"Column1":"BETHANY"},{"Column1":"BLOOMFIELD"}],
"GLDesc":[{"Column1":"Commercial"},{"Column1":"Industrial"},{"Column1":"Public"}]
}
Related
I'm working in .Net Core 2.2 with the MVC pattern. I have a Web-API controller, where I created some Endpoints with classic CRUD-methods.
Now I have everything compiling and when I debug my soluting I get an array containing a couple of JSON-formatted objects - but the system sees the output it as an array, not as JSON.
Now I want this array to become a JSON.
I've looked at this: https://www.newtonsoft.com/json/help/html/T_Newtonsoft_Json_Linq_JObject.htm
My orginal method looked like this (in controller):
[HttpGet("/ListAllItems")]
public async Task<IEnumerable<DtoModel>> ListAllItemsFromDb()
{
return await _dbProvider.ListAllItemsAsync();
}
and gave an output of:
[{"id": "GUID-STRING", "itemName": "foo"}, {"id": "GUID-STRING2", "itemName": "bar"}]
//My frontend did not recognize this as a JSON, since it is an array, and threw an exception
So I tried this in my controller instead
[HttpGet("/ListAllItems")]
public async Task<JObject> ListAllItemsFromDb()
{
var result = await _dbProvider.ListAllItemsAsync();
string output = result.ToString();
string json = JsonConvert.SerializeObject(output);
JObject obj = JObject.Parse(json);
return obj;
}
When I run this code, my error message states: "JsonReaderException: Error reading JObject from JsonReader. Current JsonReader item is not an object: String. Path '', line 1, position 60."
How do I make the array of objects into a JSON object?
Your front end might reject JSON arrays because there are some security issues with them. The article Anatomy of a Subtle JSON Vulnerability explains it. But I think it is no longer applicable, see this and this Stack Overflow question
You can however create a wrapper object to avoid returning top level JSON arrays:
public class Wrapper<T> {
public T Data {get; set;}
}
Then in your controller:
[HttpGet("/ListAllItems")]
public async Task<Wrapper<IEnumerable<DtoModel>>> ListAllItemsFromDb()
{
return new Wrapper<<IEnumerable<DtoModel>>() {
Data = await _dbProvider.ListAllItemsAsync()
};
}
The MVC infraestructure will return a JSON result like this:
{
Value: [{"id": "GUID-STRING", "itemName": "foo"}, {"id": "GUID-STRING2", "itemName": "bar"}]
}
This should make your front end happy.
JsonConvert will convert your list with no problems - calling ToString() on IEnumerable<DtoObject> might be your problem.
Pass the list in to JsonConvert and it will parse correctly.
var result = await _dbProvider.ListAllItemsAsync();
string json = JsonConvert.SerializeObject(result);
This question already has answers here:
Serialize and Deserialize Json and Json Array in Unity
(9 answers)
Closed 3 years ago.
I recently got into C# using Unity. I previously worked with JavaScript and know that they defiantly have their differences, but still have some similarities. I have used JSON with JS and it works great. Now with Unity, I want to store data of upcoming "stages" in JSON in an infinite runner game. But from my experience, JSON does not work nearly as well with C# as it does with JS. I have looked at Unity's JSON Utility but haven't figured out if it's possible to simply have a string and then convert it into an object which you could access like object.item.array[0].item which is how you'd do it in JS. Another thing that I looked at was this but as a novice to C#, I couldn't make heads or tails of it. So does C# have something like JSON, but its more integrated? I've used C# lists, can you get 3D lists with items and not just arrays? I know that they are very different languages, and what works well on one, might not on another.
I think closest to what you describe in your questions and the comments as
simply convert a JSON string into a JSONObject
would maybe be the good old SimpleJSON. Simply copy the SimpleJSON.cs and depending on your needs maybe SimpleJSONUnity.cs(provides some extensions for directly parsing to and from Vector2, Vector3, Vector4, Quaternion, Rect, RectOffset and Matrix4x4) somewhere into your Assets folder.
Then given the example json
{
"version": "1.0",
"data": {
"sampleArray": [
"string value",
5,
{
"name": "sub object"
}
]
}
}
you can simply access single fields like
using SimpleJSON;
...
var jsonObject = JSON.Parse(the_JSON_string);
string versionString = jsonObject["version"].Value; // versionString will be a string containing "1.0"
float versionNumber = jsonObject["version"].AsFloat; // versionNumber will be a float containing 1.0
string val = jsonObject["data"]["sampleArray"][0]; // val contains "string value"
string name = jsonObject["data"]["sampleArray"][2]["name"]; // name will be a string containing "sub object"
...
Using this you don't have to re-create the entire c# class representation of the JSON data which might sometimes be a huge overhead if you just want to access a single value from the JSON string.
However if you want to serialze and deserialize entire data structures you won't get happy using SimpleJSON. Given the example above this is how you would use Unity's JsonUtility
Create the c# class representation of the data yu want to store. In this case e.g. something like
[Serializable]
public class RootObject
{
public string version = "";
public Data data = new Data();
}
[Serializable]
public class Data
{
public List<object> sampleArray = new List<object>();
}
[Serializeable]
public class SubData
{
public string name = "";
}
Then fill it with values and parse it to JSON like
var jsonObject = new RootObject()
{
version = "1.0",
data = new Data()
{
sampleArray = new List<object>()
{
"string value",
5,
new SubData(){ name = "sub object" }
}
}
};
var jsonString = JsonUtility.ToJson(jsonObject);
And to convert it back to c# either if jsonObject was not created yet
jsonObject = JsonUtility.FromJson<RootObject>(jsonString);
otherwise
JsonUtility.FromJsonOverwrite(jsonString, jsonObject);
JSON is just how objects are represented in JavaScript. While C# can use JSON, you'll probably have a much easier time defining your own custom classes. Using classes, you can define all the properties you'll need, string them together into a list, etc.. Hope this helps.
Given an array in the JSON, I am trying to find the best way to convert it to JArray.
For example - consider this below C# code:
var json = #"{
""cities"": [""London"", ""Paris"", ""New York""]
}";
I can read this JSON into JObject as -
var jsonObject = JObject.Parse(json);
Now I will get the "cities" field.
var jsonCities = jsonObject["cities"];
Here I get jsonCities as type JToken.
I know jsonCities is an array, so I would like to get it converted to JArray.
The way I do currently is like this -
var cities = JArray.FromObject(jsonCities);
I am trying to find out is there any better way to get it converted to JArray.
How are other folks using it?
The accepted answer should really be the comment by dbc.
After the proposed casting to JArray, we can validate the result by checking for null value:
var jsonCities = jsonObject["cities"] as JArray;
if (jsonCities == null) return;
...do your thing with JArray...
Edit:
As stated by dbc, a JToken that represent a JArray, is already a JArray.
That is if the JToken.Type equals an JTokenType.Array. If so it can be accessed by using the as JArray notation. When the as casting notation is used, a failed cast will render a null value, as explained here. That makes it convenient for validating that you actually got a JArray you can use.
JArray.FromObject(x) takes an object, so it can be used with anything that can be represented as an object and thus certainly an JToken.
In this case we know that we can simply cast from JToken to JArray, so it gives us another possibility. I would expect it to be faster, but I leave that as an exercise for someone else to figure out.
Here we make use of c# classes to store the contents of our jsonString by deserialising the string.
Below is a basic example.
For Further Reading I will point you to the Newtonsoft.Json website.
https://www.newtonsoft.com/json/help/html/DeserializeObject.htm
class Program
{
static void Main(string[] args)
{
var json = #"{""cities"": [""London"", ""Paris"", ""New York""]}";
MyObject result = JsonConvert.DeserializeObject<MyObject>(json);
foreach (var city in result.Cities)
{
Console.WriteLine(city);
}
Console.ReadKey();
}
public class MyObject
{
[JsonProperty("cities")]
public List<string> Cities { get; set; }
}
}
I am trying to consume a web service that claims to return JSON, but actually always returns JSONP. I don't see a way to change that service's behavior.
I would like to use NewtonSoft Json.Net to parse the result. I have declared a class, let's call it MyType that I want to deserialize the inner JSON result into.
JSONP:
parseResponse({
"total" : "13,769",
"lower" : "1",
"upper" : "20"})
As you can see this is not correct JSON as it has parseResponse( prefix and ) suffix. While this example is very simple, the actual response can be quite long, on the order of 100Ks.
MyType:
public class MyType
{
public Decimal total;
public int lower;
public int upper;
}
After I get my web service response into a stream and JsonTextReader I try to deserialize like this:
(MyType)serializer.Deserialize(jsonTextReader, typeof(MyType));
Of course I get null for a result because there is that pesky parseResponse with round brackets.
I've taken a look at this question which unfortunately does not help. I'm actually using a JsonTextReader to feed in the JSON, rather than a string (and prefer so to avoid the performance hit of creating huge a string). Even if I'd use the suggestion from that question, it looks dangerous as it uses a global replace. If there is no good way to use a stream, an answer with safe parsing of strings would be okay.
If I interpret your question as follows:
I am trying to deserialize some JSON from a Stream. The "JSON" is actually in JSONP format and so contains some prefix and postfix text I would like to ignore. How can I skip the prefix and postfix text while still reading and deserializing directly from stream rather than loading the entire stream into a string?
Then you can deserialize your JSON from a JSONP stream using the following extension method:
public static class JsonExtensions
{
public static T DeserializeEmbeddedJsonP<T>(Stream stream)
{
using (var textReader = new StreamReader(stream))
return DeserializeEmbeddedJsonP<T>(textReader);
}
public static T DeserializeEmbeddedJsonP<T>(TextReader textReader)
{
using (var jsonReader = new JsonTextReader(textReader.SkipPast('(')))
{
var settings = new JsonSerializerSettings
{
CheckAdditionalContent = false,
};
return JsonSerializer.CreateDefault(settings).Deserialize<T>(jsonReader);
}
}
}
public static class TextReaderExtensions
{
public static TTextReader SkipPast<TTextReader>(this TTextReader reader, char ch) where TTextReader : TextReader
{
while (true)
{
var c = reader.Read();
if (c == -1 || c == ch)
return reader;
}
}
}
Notes:
Prior to constructing the JsonTextReader I construct a StreamReader and skip past the first '(' character in the stream. This positions the StreamReader at the beginning of the actual JSON.
Before deserialization I set JsonSerializerSettings.CheckAdditionalContent = false to tell the serializer to ignore any characters after the end of the JSON content. Oddly enough it is necessary to do this explicitly despite the fact that the default value seems to be false already, since the underlying field is nullable.
The same code can be used to deserialize embedded JSONP from a string by passing a StringReader to DeserializeEmbeddedJsonP<T>(TextReader reader);. Doing so avoids the need to create a new string by trimming the prefix and postfix text and so may improve performance and memory use even for smaller strings.
Sample working .Net fiddle.
It looks like it's returning JSONP. Kind of weird that a webservice would do that by default, without you including "?callback". In any case, if that's just the way it is, you can easily use a RegEx to just strip off the method call:
var x = WebServiceCall();
x = Regex.Replace(x, #"^.+?\(|\)$", "");
First of all let me tell you one thing that I am posting this question is just for eagerness and to increase my knowledge. Hope you can clear my doubts !
Now lets come to the point
I got this question from my previous question-answer
Actually the problem is if I use
List<oodleListings> listings;
instead of
oodleListings[] listings;
It works fine !! I can deserialize my json string easily.
Now the problem is why array is not supported while deserializing json ?
What is the actual reason to use List instead of array ?
Your problem is not related with Arrays or Lists.
See the example classes below
public class TestClassList
{
public List<User> users;
}
public class TestClassArray
{
public User[] users;
}
public class User
{
public string user;
}
and assume your input string is
string json1 = "{ users:[{user:'11'},{user:'22'}] }";
var obj1= ser.Deserialize<TestClassList>(json1);
var obj2 = ser.Deserialize<TestClassArray>(json1);
both deserializations will work..
But if you try to deserialize this string string json2 = "{ users:{user:'11'} }";
var obj3 = ser.Deserialize<TestClassList>(json2);
var obj4 = ser.Deserialize<TestClassArray>(json2); //<--ERROR
you will get error in the second line (Althoug first line doesn't give an error, it doesn't return a valid object either).
As a result: The second json string does not contain an array of users, this is why you get No parameterless constructor defined for type of 'User[]'.
List<T> does not have a fixed length, so you are free to Add items to that object, without knowing its size. List is definitely the more flexible/functional class, but as a side-effect, it has a larger memory footprint.
Also, an object of type List<oodleListing> will have a method AddRange method that takes a parameter of oodleListing[] so you could always deserialize and then add to your generic class.
There is nothing wrong with Array or List. I just tried your code and it works without any issue for both Array and List.
In your previous question you didn't give the JSON serialized string, other wise it would have been solved there it self. You can check this post from ASP.Net.