I am trying to create a json formatted string using c# in UWP without JSON.Net, but I am just not understanding how to get there. Let's say I wanted to create the following json dynamically:
[{"id":130},{"id":131},{"id":132},{"id":133},{"id":134}]
From everything I have read, it would seem that I need a class that defines the content of my json. For example:
class accountTypes
{
public int id { get; set; }
public string type { get; set; }
}
From there, it would seem that I only need to create a list of type "accountTypes" and then add each "id" to the list.
List<accountTypes> jsonList = new List<accountTypes>();
int numOfChildren = AccountTypesList.Children.Count;
for (int i = 0; i < numOfChildren; i++)
{
if (((CheckBox)AccountTypesList.Children[i]).IsChecked == true)
{
jsonList.Add(new accountTypes() { id = (int)(double)((CheckBox)AccountTypesList.Children[i]).Tag });
}
}
While I am 99% sure that the above code is very flawed, it does not crash on me, so that is a start at least. What I am struggling with now though is how I would serialize the list "jsonList". Everything I have read thus far either points to JSON.net or the JavaScriptSerializer Class, and not Windows.Data.Json. If I could see a simple example on how to serialize json using Windows.Data.Json, then I could at least visualize what is going on with my list and could correct it accordingly. That being said, how do I serialize an array or a list using Windows.Data.Json?
First of all, there's no built-in JSON-serializer that handles all the mapping for you. This is exactly what JSON.NET is doing for you. Therefore, you have to take the manual and long way.
To create exactly this result:
[{"id":130},{"id":131},{"id":132},{"id":133},{"id":134}]
You have to use the JsonArray class. For example, pass your jsonList object to a method like this:
public string ToJson(List<accountTypes> objectList)
{
var jArray = new JsonArray();
foreach (var at in objectList)
{
jArray.Add(ToJson(at));
}
return jArray.ToString();
}
Whereas you use this method to create a JsonObject for your class object itself (as manual step as well):
public JsonObject ToJson(accountTypes at)
{
var jObj = new JsonObject();
jObj.SetNamedValue("id", JsonValue.CreateNumberValue(at.id));
return jObj;
}
Related
I am developing an app on UWP.
When I connect with a server api and I get the next response I don't have problems.
{"value":"Login successfull","sessionId":"a95077855b05ed0fec5d7fa3abafa126e15aba2a"}
I can get information in the following way:
JsonObject jsonObject = JsonObject.Parse(jsonString);
string token = jsonObject["sessionId"].GetString();
string value = jsonObject["value"].GetString();
but my problem is when i get the next response of the api:
[{"person":{"name":"name1","country":"Spain","city":"user_city","phone":null}},{"person":{"name":"name2","country":"Turkey","city":"user_city","phone":"1111111"}},{"person":{"name":"name3","country":"Argentina","city":"user_city","phone":"22222"}},{"person":{"name":"name4","country":"Argentina","city":"user_city","phone":"33333"}}]
How can I loop through the JSON and get all the people that match a condition?
I have to do with "Windows.Data.Json"
If interested in a solution using only Windows.Data.Json namespace, here it is:
var rootValue = JsonValue.Parse(jsonString);
foreach (var item in rootValue.GetArray())
{
var unamedObject = item.GetObject();
var personObject = unamedObject["person"].GetObject();
System.Diagnostics.Debug.WriteLine(personObject["name"].GetString());
System.Diagnostics.Debug.WriteLine(personObject["country"].GetString());
System.Diagnostics.Debug.WriteLine(personObject["city"].GetString());
System.Diagnostics.Debug.WriteLine(personObject["phone"].GetString());
}
Why would somebody pick Windows.Data.Json over Newtonsoft's Json.net?
If your JSON needs are simple, you can reduce the size of your app ~1 MB by choosing Windows.Data.Json because it is part of the operating system.
I would recommend you try out Json.net nuget package and deserialise the json payload to classes through that.
A good tutorial can be found here: http://windowsapptutorials.com/windows-phone/general/deserialize-json-data-using-newtonsoft-json-net-library/
But if you search you'll find more.
In short, you first copy paste your json and use Visual Studio > File > Paste Special > To paste to classes ( first open an empty cs file and set your cursor inside it ).
After that you use JsonConvert.DeserializeObject<RootObject>() to actually parse the json string.
Once parsed you'll have an array of items if your original json also defined an array.
Note RootObject is the first class object in the generated classes in Visual Studio
There are ways to do it without external libraries, if that is the real reason for the stipulation of Windows.Data.Json.
I'd likely do it something like this...
First I'd make some classes representing the returning JSON:
public class RootObject
{
public Person person { get; set; }
}
public class Person
{
public string name { get; set; }
public string country { get; set; }
public string city { get; set; }
public string phone { get; set; }
}
Then add a little method to deserialize:
public static T Deserialize<T>(string json)
{
var bytes = Encoding.Unicode.GetBytes(json);
using (var ms = new MemoryStream(bytes))
{
var serializer = new System.Runtime.Serialization.Json.DataContractJsonSerializer(typeof(T));
return (T)serializer.ReadObject(ms);
}
}
And finally deserialize and query that result like so:
var persons = Json.Deserialize<List<RootObject>>(textBox.Text);
var peeps = (from p in persons
where p.person.name.StartsWith("name")
select p).ToList();
I am playing with the Harvest API and I'm trying to automatically map the entities as easy as possible, unfortunately when I do a request like GET /projects it generates a result like so:
[{
project: {
name: "Test"
}
},
{
project: {
name: "Test 2"
}]
In RestSharp, I can't directly do this:
client.Execute<List<Project>>(request)
Because it is going to look for a property called Project. So I have to make another class that has that property, and call it like this:
client.Execute<List<ProjectContainer>>(request)
I don't want to make a 'container' class for every entity, so I thought I found a clever solution to make one class I can use on all:
public class ListContainer<T> where T : IHarvestEntity
{
public T Item { get; set; }
}
But, of course, the deserializer has no idea it needs to map the entity name (or "Project") to the property Item. In the restsharp documentation I found that I could use [DeserializeAs(Name = "CustomProperty")] to tell the deserializer which field to map to this property. However, attributes do only allow constants, which means I can't do:
[DeserializeAs(Name = typeof(T).FullName)]
public T Item { get; set; }
Does anyone know a clever solution to this? So i don't have to create 10 different container classes?
I suggest you use the XPath equivalent for Json. With Json.NET you can parse the string and create a dynamic object.
With SelectToken you can query values, or using Linq.
The code looks something like this (I did not test it):
// execute the request
RestResponse response = client.Execute(request);
var content = response.Content; // raw content as string
JObject o = JObject.Parse(content);
IList<string> projectNames = o.SelectToken("project").Select(s => (string)s.name).ToList();
You can code the paths or configure the paths anyway you like.
--- Edit ---
Here's an example that I tested, converting the json string to a list of projects.
var projects = JArray.Parse(response.Content).Select(r => new Project(r["project"]["name"].Value<string>())).ToList();
To keep it really simple, you can use List<dynamic> and access the property/properties by name with a one-liner.
var names = client.Execute<List<dynamic>>(request).Data.Select(
item => item["project"]["name"]).ToList(); // list of names
If this is not sufficient, then you could improvise your own mapper and extract a collection of e.g. Project instances:
var projects = client.Execute<List<dynamic>>(request).Data.Select(
item => Map<Project>(item)).ToList(); // list of Project instances
where Map method could be something like
public T Map<T>(dynamic item) where T : class
{
// inline for clarity
var mappings = new Dictionary<Type,Func<dynamic,object>>
{
{ typeof(Project), map => new Project(map["project"]["name"]) }
};
return (T)mappings[typeof(T)].Invoke(item);
}
given Project is defined as
public class Project
{
public Project(string name)
{
Name = name;
}
public string Name { get; set; }
}
I am really confused as to why I can't access any data that I have deserialized from Json string. When I step through the process I can see that the data is there, I just can't access it.
I am placing the data into Dictionary<string, object>, it's Count is 2. It contains object{object[]} (which I read as an ArrayList of objects?), and an object with response information.
I'm not too fussed about the response information I need to access the objects in the ArrayList. I'm having no such luck, my code is below:
var output = new JavaScriptSerializer().Deserialize<Dictionary<string, object>>(await response.Content.ReadAsStringAsync());
I have tried to get just the ArrayList using output["List"] (List is the objects key) and can still see all of the objects inside but still can't access them. It's probably a simple fix, it always is, but I have been staring at this problem all day and just can't make sense of it so could do with another pair of eyes.
Thanks
EDIT
The Json string is in the following format:
{"List":[{"Id":1,"intProperty":2,"boolProperty":false},{"Id":2,"intProperty":3,"boolProperty":false},{"Id":4,"intProperty":5,"boolProperty":false}],"ResponseInformation":{Other info here}}
Deserialize it into a class:
public class ListClass
{
public int Id;
public int IntProperty;
public bool boolProperty;
}
and then
var output = new JavaScriptSerializer().Deserialize<Dictionary<string, ListClass>>(await response.Content.ReadAsStringAsync());
And that should work!
I have figured out a long winded way of getting the information I need, If anyone can see a way to condense the code I'm open to suggestions :)
First I created my Currency class
public class Currency
{
public int CurrencyId { get; set; }
public int GlobalCurrencyId { get; set; }
public bool Archived { get; set; }
}
Next I deserialized my Json as I did in my question
var output = new JavaScriptSerializer().Deserialize<Dictionary<string, object>>(await response.Content.ReadAsStringAsync());
Next is the long winded bit; I used a foreach statement to get each element of my output variable. It was then made clear that the data inside was an array of dictionary objects so I created a list of Currency class objects:
var currencyObject = output["List"];
List<Currency> currencyList = new List<Currency>();
Currency item;
ArrayList myList = currencyObject as ArrayList;
foreach (object element in myList)
{
Dictionary<string, object> L1 = element as Dictionary<string, object>;
item = new Currency();
item.CurrencyId = Convert.ToInt32(L1["CurrencyId"]);
item.GlobalCurrencyId = Convert.ToInt32(L1["GlobalCurrencyId"]);
item.Archived = Convert.ToBoolean(L1["Archived"]);
currencyList.Add(item);
}
Figured it out in just two lines!!
var json = response.Content.ReadAsStringAsync().Result;
IList<Currency> output = new JsonSerializer().Deserialize<IList<Currency>>(new JsonTextReader(new StringReader(json)));
I have a below code that used JSON.stringify to the object then passed it on POST method (Please see below Javascript code). I'm getting those values on the backend using C#. My problem is, how could I convert/manipulate/access the stringified values. Please see below C# code
Javascript:
var json_db = JSON.stringify(selectedDbInfo);
$.post("../FormActions/DatabaseChanges.aspx", { action: "savedb", orderNumber: orderNumber, selectedDb: json_db},
function (response) {
alert('ok');
});
C#:
var dbValue = c.Request.Params["selectedDb"];
below is the result value of dbValue
"[{\"dbname\":\"BASINS\",\"distance\":\"0\"},{\"dbname\":\"BROWNFIELD\",\"distance\":\"0.5\"},{\"dbname\":\"BRS\",\"distance\":\"0\"}]"
You need to parse the JSON into a .NET array or List.
Many use json.NET for this: http://james.newtonking.com/json
At a push you could use some string manipulation to populate your objects one by one, but I wouldn't recommend that.
There are many samples here on SO.
if you're just want to convert it dictionary look here:
How can I deserialize JSON to a simple Dictionary<string,string> in ASP.NET?
However, there's a built in mechanism in ASP.NET MVC that serializes automatically your json param to predefined objects at your convenient.
You may define a class having the fields like dbname and distance as properties. Then you may deserialize the json string dbValue into a list of that type using NewtonSoft.Json. Please see the code below:
var list = JsonConvert.DeserializeObject<List<RootObject>>(dbValue);
foreach (var item in list)
{
Console.WriteLine(string.Format("dbname: {0}, distance: {1}", item.dbname, item.distance));
}
Ans the definition of RootObject is as simple as you guess:
public class RootObject
{
public string dbname { get; set; }
public string distance { get; set; }
}
Create a custom serializable data contract class, say DatabaseDistance, with following properties:
[DataMember(Name = "dbname")]
private string name;
[DataMember(Name = "distance")]
private double distance;
and use following method for deserialization:
public static T FromJSON<T>(string jsonValue, IEnumerable<Type> knownTypes)
{
//validate input parameters here
T result = default(T);
try
{
using (MemoryStream stream = new MemoryStream(Encoding.Unicode.GetBytes(jsonValue)))
{
DataContractJsonSerializer serializer = new DataContractJsonSerializer(typeof(T), knownTypes);
result = (T)serializer.ReadObject(stream);
}
}
catch (Exception exception)
{
throw new Exception("An error occurred while deserializing", exception);
}
return result;
}
pass list of your objects as type parameter
The web service I consume responces with json data.
it gives resultObject as array:
resultObject:[{object1}, {object2},...] if there more then one object
and it returns
resultObject:{object1} if there only one object.
for serializing in .NET I created a "static" structure of classes to map json schema. But if in one case i've got an array (list) of objects an in other case just one object, how is it possible to handle this situation?
I have found a plethora of ugly solutions to this one, but so far goes:
If you use the System.Web.Script.Serialization.JavaScriptSerializer you have very limited control. If the result data type is simple, you could simply use the DeserializeObject method; it will translate everything into Dictionary and the "resultObject" property will in the first case be a Dictionary while the latter case will turn it into an array of such dictionary. It will not save you the headache of the final translation, but you will get the data into dictionaries which could be considered a first step.
I also attempted to use the KnownTypes and the DataContractJsonSerializer, but alas the datacontract serializer needs "hints" in the form of specially named properties to aid it deserializing. (Why am I using the KnownType attribute wrong?). This is a hopeless strategy if you don't have any control of the serialization which I guess is the case for you.
So now we are down to the butt-ugly solutions of which trial-and-error is my first choice:
When using the ScriptSerializer the conversion will fail with an InvalidOperationException if anything is wrong. I then created two data types one with data-as-arrays and one where data is a single instance (the DataClass is my invention since you do not specify the data types):
[DataContract]
public class DataClass
{
[DataMember]
public string FirstName { get; set; }
[DataMember]
public int BirthYear { get; set; }
public override string ToString()
{
return "FirstName : '" + FirstName + "', BirthYear: " + BirthYear;
}
}
[DataContract]
public class ResultSingle
{
[DataMember]
public DataClass Data { get; set; }
}
[DataContract]
public class ResultArray
{
[DataMember]
public List<DataClass> Data { get; set; }
}
Using these data types it is possible to translate using
JavaScriptSerializer jSer = new JavaScriptSerializer();
var one = jSer.Deserialize<ResultSingle>(jsonWithSingleInstance);
var many = jSer.Deserialize<ResultArray>(jsonWithArray);
But this of course require you to known the data type in advance and you get two different result types. Instead you could choose to always convert to ResultArray. If you get an exception you should convert as ResultSingle and then instantiate the ResultArray and manually add the data object to the Data list:
static ResultArray ConvertJson(string json)
{
ResultArray fromJson;
JavaScriptSerializer jSer = new JavaScriptSerializer();
try
{
fromJson = jSer.Deserialize<ResultArray>(json);
return fromJson;
}
catch (InvalidOperationException)
{
var single = jSer.Deserialize<ResultSingle> (json);
fromJson = new ResultArray();
fromJson.Data = new List<DataClass>();
fromJson.Data.Add(single.Data);
return fromJson;
}
}
static void Main(string[] args)
{
var jsonWithSingleInstance = "{\"Data\":{\"FirstName\":\"Knud\",\"BirthYear\":1928}}";
var jsonWithArray = "{\"Data\":[{\"FirstName\":\"Knud\",\"BirthYear\":1928},{\"FirstName\":\"Svend\",\"BirthYear\":1930}]}";
var single = ConvertJson(jsonWithSingleInstance);
var array = ConvertJson(jsonWithArray);
}
I do not say this is a beautiful solution (it isn't), but it should do the job.
You could also look at json.net which seem to be the json serializer of choice in .NET: How to install JSON.NET using NuGet?
Well, my service provider finally said that it is really a bug.
http://jira.codehaus.org/browse/JETTISON-102
says that is it because of java version that they use.