I'm new to the REST/JSON interface.
I'm working in VS 2013 C#, Framework is 4.5.
Right now I've successfully created items on a list in Sharepoint, using a JSON payload similar to this:
{ '__metadata': { 'type': 'SP.Data.ABCs_x0020_for_x0020_TAC_x0020_SiebelListItem' },
'Priority':'A',
'Requirements_x0020_Status':'Fully Documented',
'Status':'Under Consideration',
'Description':'This is a test',
'ABC_x0020_Type':'Enhancement',
'Title':'Testing: 921253434',
'Business_x0020_Unit_x0020_Affect':'TAC',
'AssignedToId':'1',
'Submitted_x0020_by':'sdsd',
'Applies_x0020_To':'Screens/Views',
'Screen_x002f_View_x002f_Module':'CSR'}
I was manually creating the JSON payload and decided to try out some objects that might help with the Serialization/Deserialization.
Here is the code:
ABCItem item = new ABCItem();
item.Title = "Testing " + ran.Next();
item.ABC_x0020_Type = "Enchancement";
item.Applies_x0020_To = "Screens/View";
item.Priority = "A";
item.Requirements_x0020_Status = "Fully Documented";
item.Screen_x002f_View_x002f_Module = "CSR";
item.Business_x0020_Unit_x0020_Affect = "TAC";
item.Submitted_x0020_by = "Brian Hintze";
item.Status = "Under Consideration";
item.AssignedToId = 1;
item.Description = "The quick brown fox jumped over the lazy dog and then drank a pint of beer.";
string json = JsonConvert.SerializeObject(item);
Unfortunately I can't figure out how to get the __metadata part of the JSON payload to get added correctly. I've tried this
item.__metadata = "{ 'type': 'SP.Data.ABCs_x0020_for_x0020_TAC_x0020_SiebelListItem' }";
But that didn't work.
I've tried fiddling around the MetaDataSettings, but so far I can't figure out the right combination.
string json = JsonConvert.SerializeObject(item,new JsonSerializerSettings
{
TypeNameHandling = TypeNameHandling.All,
// $type no longer needs to be first
MetadataPropertyHandling = MetadataPropertyHandling.Default
});
Any help would be appreciated. I'm sure it is something fairly basic that I'm missing.
thanks,
lee
The JSON serializer will convert objects to JavaScript objects.
Instead of making item.__metadata a string value, try making it an object with a member property called Type that equals "SP.Data.ABCs_x0020_for_x0020_TAC_x0020_SiebelListItem".
You probably want to make the property __metadata be a reference to its own class. After all, this is a complex json object.
Using json2csharp.com 1 you can see that your ABCItem class should look like
public class Metadata
{
public string type { get; set; }
}
public class ABCItem
{
public Metadata __metadata { get; set; }
public string Priority { get; set; }
(...)
}
Related
Suppose I have the following:
var b = true;
var f = "{ \"templateName\": \"name\", \"Active\": \"" +b + "\"}";
That b value does not work for me :( , I tried different scenario's with no luck.
The proper way of doing this is to work with objects directly. Then you can serialize to whatever format you want (if you want JSON, JSON.NET is what you should use).
For instance, you should have a class that looks something like this:
public class TestClass
{
public bool Active { get; set; }
public string TemplateName { get; set; }
}
This is a class that represents your JSON object, but instead of modifying strings and dealing with that headache, we just deal with objects.
In your code you can instantiate and/or modify an instance of that object:
var testObj = new TestClass()
{
Active = true,
TemplateName = "SomeName"
};
//changed my mind, I want Active to be false now
testObj.Active = false;
Then with the power of JSON.NET you can serialize this object into JSON:
string jsonString = JsonConvert.SerializeObject(testObj);
I'm trying to parse to a C# object a string containing a JSON that looks like that :
I know it's not really valid json but I can't choose it, it's sent by a device. That's why I've tried to replace the [] by {} to make it look like a valid object.
[2, "2", "text", {Object}]
I've created the following class:
public class MyClass
{
[JsonProperty(Order = 0)]
public int TypeRequest { get; set; }
[JsonProperty(Order = 1)]
public string UniqueID { get; set; }
[JsonProperty(Order = 2)]
public string Action { get; set; }
[JsonProperty(Order = 3)]
public JObject Payload { get; set; }
}
I want to parse the {Object} later (I need to know the "Action" property first because the object depends on the action).
So far I've done :
string userMessage = "[2, "2", "text", {Object}]";
if (userMessage.Length > 2)
{
// We need to remove the first [ and the last ] to be able to parse into a json object
StringBuilder sb = new StringBuilder(userMessage);
sb[0] = '{';
sb[sb.Length - 1] = '}';
userMessage = sb.ToString();
}
JavaScriptSerializer jsonSerializer = new JavaScriptSerializer();
MyClass objectJSON = jsonSerializer.Deserialize<MyClass >(userMessage);
But it doesn't work I get the following exception:
Invalid object passed in, ':' or '}' expected. (3): {Object}}
I've also tried with JObject.Parse instead and I got:
Invalid JavaScript property identifier character: ,. Path '', line 1,
position 2.
Do you know how to do it? I would like to avoid having to split my JSON by commas and have the cleanest way to do it.
It's not really a valid JSON because of {Object} so I removed it. You can technically do json.Replace("{Object}", "something else") to make it easier. Because you deal with different types in array, it may not be a one step process. Here is an idea for you:
var json = "[2, \"2\", \"text\"]";
var array = JsonConvert.DeserializeObject<JArray>(json);
foreach (var item in array)
{
switch (item.Type)
{
case JTokenType.Integer:
// todo: your parsing code
break;
case JTokenType.String:
break;
// etc.
}
}
I used JSON.NET library to parse JSON. You can install it using nuget:
Install-Package Newtonsoft.Json
If you can, I'd recommend you to fix the JSON source to provide you with a valid JSON that can be parsed to an object without use of low-level classes like JToken, JArray, JObject etc.
I'm looking for a way to do deserialization from Json to be version dependent using the data within the Json itself.
I'm targeting to use ServiceStack.Text.JsonDeserializer, but can switch to another library.
For example, I'd like to define a data in JSON for v1.0 to be:
{
version: "1.0"
condition: "A < B"
}
and then, a next version of the data (say 2.0) to be:
{
version: "2.0"
condition: ["A < B", "B = C", "B < 1"]
}
At the end, I want to be able to validate version of the data to know how to deserialize the JSON correctly.
UPDATE:
It looks like there is no any kind of implicit support for version-dependent JSON (de)serialization in known products.
The right solution seems to be to split the task by (de)serializing only version part and then use implicit (de)serializing for the correct type(s).
Gratitudes to everyone who shared knowledge and thoughts on the problem.
What you can do is either the following:
Create a base class for the data objects you want to deserialize that contains a version field and nothing else.
Make the data classes for your different versions be derived classes of this base class.
When you deserialize your data object, first, deserialize it as an instance of your base class - so now you have a POCO object that contains the version number. You can use this to decide which of your derived data classes you should use to deserialize your data (in the simplest case, you can do a switch/case and handle each version individually)
An example (using System.Web.Script.Serialization.JavaScriptSerializer):
class BaseClass
{
public int version { get; set; }
}
class FirstVersion: BaseClass
{
public string condition { get; set; }
}
class SecondVersion: BaseClass
{
public IEnumerable<string> condition { get; set; }
}
public void Deserialize (string jsonString)
{
JavaScriptSerializer serializer = new JavaScriptSerializer();
BaseClass myData = serializer.Deserialize<BaseClass>(jsonString);
switch (myData.version)
{
case 1:
FirstVersion firstVersion = serializer.Deserialize<FirstVersion>(jsonString);
// ...
break;
case 2:
SecondVersion secondVersion = serializer.Deserialize<SecondVersion>(jsonString);
// ...
break;
}
}
As you can see, this code deserializes the data twice - that may be a problem for you if you are working with large data structures. If you want to avoid that at all costs, you either have to give up static typing or modify the data model of your application.
And here is how it looks like with dynamic:
public void Deserialize (string jsonString)
{
JavaScriptSerializer serializer = new JavaScriptSerializer();
dynamic myData = serializer.Deserialize<object>(jsonString);
if (myData ["version"] == 1) {
...
}
}
There is also the option to write your own custom JavaScriptConverter. That is a lot more work, but I'm pretty sure you can achieve what you want and it will look nicer.
Another advice to consider is never to remove properties from your JSON structure. If you need to modify a property, keep the old one and add a new one instead - this way, old code can always read data from newer code. Of course, this can get out of hand pretty quickly if you modify your data structures a lot...
In Java, you could use Google's GSON library, as it has a built-in support for versioning. I haven't looked into it, but it is open source and if it's really important to you, I guess you can port the implementation to a different language.
I suggest that you use json.net is it allows you to add your custom type converts which can be used for versioning.
The problem is not serialization as it will always use the current schema. The problem is when the client uses a different type version that the server that receives the object.
What you need to do is to check the version programatically in your type converter and the convert the value by yourself (in this case convert the string to an array).
Documentation: http://www.newtonsoft.com/json/help/html/CustomJsonConverter.htm
You might want to use the NewtonSoft.Json NuGET package.
This is kind of a standard within the .NET community. It is also often referred to as Json.NET
You can use it like this (example from official website):
Product product = new Product();
product.Name = "Apple";
product.ExpiryDate = new DateTime(2008, 12, 28);
product.Price = 3.99M;
product.Sizes = new string[] { "Small", "Medium", "Large" };
string output = JsonConvert.SerializeObject(product);
//{
// "Name": "Apple",
// "ExpiryDate": "2008-12-28T00:00:00",
// "Price": 3.99,
// "Sizes": [
// "Small",
// "Medium",
// "Large"
// ]
//}
Product deserializedProduct = JsonConvert.DeserializeObject<Product>(output);
If you are willing to switch to JSON.net, then there is a simpler way of doing it. You don't have to use a BaseClass containing version and you don't have to parse twice. The trick is to use JObject and then query JSON for the version:
JObject obj = JObject.Parse(json);
string version = obj.SelectToken("$.Version")?.ToString();
Then you can proceed as Sándor did with the bonus part that you can use JObject to get your dto instead of re-reading json:
ConditionsDto v1Dto = obj.ToObject<ConditionsDto>(readSerializer);
Putting it all together:
public static ConditionsBusinessObject Parse(string json)
{
JObject obj = JObject.Parse(json);
string version = obj.SelectToken("$.Version")?.ToString();
JsonSerializer readSerializer = JsonSerializer.CreateDefault(/*You might want to place your settings here*/);
switch (version)
{
case null: //let's assume that there are some old files out there with no version at all
//and that these are equivalent to the version 1
case "1":
ConditionsDto v1Dto = obj.ToObject<ConditionsDto>(readSerializer);
if (v1Dto == null) return null; //or throw
List<string> convertedConditions = new List<string> {v1Dto.Condition}; //See what I've done here?
return new ConditionsBusinessObject(convertedConditions);
case "2":
ConditionsDtoV2 v2Dto = obj.ToObject<ConditionsDtoV2>(readSerializer);
return v2Dto == null ? null //or throw
: new ConditionsBusinessObject(v2Dto.Condition);
default:
throw new Exception($"Unsupported version {version}");
}
}
For reference here are the classes that I have:
public class ConditionsDto
{
public string Version { get; set; }
public string Condition { get; set; }
}
public class ConditionsDtoV2
{
public string Version { get; set; }
public List<string> Condition { get; set; }
}
public class ConditionsBusinessObject
{
public ConditionsBusinessObject(List<string> conditions)
{
Conditions = conditions;
}
public List<string> Conditions { get; }
}
and a couple of tests to wrap it up:
[Test]
public void TestV1()
{
string v1 = #"{
Version: ""1"",
Condition: ""A < B""
}";
//JsonHandler is where I placed Parse()
ConditionsBusinessObject fromV1 = JsonHandler.Parse(v1);
Assert.AreEqual(1, fromV1.Conditions.Count);
Assert.AreEqual("A < B", fromV1.Conditions[0]);
}
[Test]
public void TestV2()
{
string v2 = #"{
Version: ""2"",
Condition: [""A < B"", ""B = C"", ""B < 1""]
}";
ConditionsBusinessObject fromV2 = JsonHandler.Parse(v2);
Assert.AreEqual(3, fromV2.Conditions.Count);
Assert.AreEqual("A < B", fromV2.Conditions[0]);
Assert.AreEqual("B = C", fromV2.Conditions[1]);
Assert.AreEqual("B < 1", fromV2.Conditions[2]);
}
In a normal real world application, the //See what I've done here? part is where you will have to do all your conversion chores. I didn't do anything smart there, I just wrapped the single condition to a list to make it compatible with the current business object. As you could guess though, this can explode as the application evolves. This answer in softwareengineering SE has more details in the theory behind versioned JSON data so you might want to have a look in order to know what to expect.
One final word about performance impact of reading to JObject and then converting to the dto is that I haven't done any measurements but I expect it to be better than parsing twice. If I find out that this is not true, I will update the answer accordingly.
Take a look at
System.Web.Script.Serialization.JavaScriptSerializer
Sample
var ser = new JavaScriptSerializer();
var result = (IReadOnlyDictionary<string, object>)ser.DeserializeObject(json);
if(result["version"] == "1.0")
{
// You expect a string for result["condition"]
}
else
{
// You expect an IEnumerable<string> for result["condition"]
}
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'm facing a wierd problem when converting Json Unicode(?) to UTF8
"V\u00E4xj\u00F6" should be "Växjö"
Right now it seems like I've tried everything possible, but no luck.
Any coding ninjas out there that may sit on a solution? I'm sure it's fairly easy but still can't seem to figure it out.
Thank you
As Tomalak pointed out, it can be done using the System.Web.Helpers.Json.Decode method (no external libraries, .NET Framework). You need to build a simple JSON object to fetch the decoded text:
// helper class
public class Dummy
{
public String Field { get; set; }
}
//
var value = "V\u00E4xj\u00F6";
var sb = new StringBuilder();
sb.Append("{");
sb.Append(String.Format(#"""Field"" : ""{0}""", value));
sb.Append("}");
var dummy = Json.Decode(sb.ToString());
Console.WriteLine(dummy.Field);
// it works also without helper class
var obj = Json.Decode(sb.ToString());
Console.WriteLine(obj.Field);
The output is:
Växjö
Växjö
One possibility would be to use the Json.NET library to decode the string (or maybe for the whole JSON handling?). The deserializer decodes the string automatically. My test code looks like this:
// placeholder for the example
public class Sample
{
public String Name { get; set; }
}
//
var i = #"{ ""Name"" : ""V\u00E4xj\u00F6"" }";
var jsonConverter = Newtonsoft.Json.JsonConvert.DeserializeObject(i);
Console.WriteLine(jsonConverter.ToString());
//
var sample = Newtonsoft.Json.JsonConvert.DeserializeObject<Sample>(i);
Console.WriteLine(sample.Name);
The output is:
{
"Name": "Växjö"
}
Växjö