ServiceStack Deserialize Json (with types) to List of specific type - serialization

I have this json:
{
"$type": "System.Collections.Generic.List<MyType>",
"$values": [
{
"$type": "MyType",
"o": 7.54,
"t": 1619002800000,
"n": 3
},
{
"$type": "MyType",
"o": 7.53,
"t": 1619005140000,
"n": 3
}
]
}
I want to deserialize it back into a List<MyType>. I thought there would be an easy way to do that some thing like this:
var myList = json.FromJson<MyType>();
but that doesn't work.
I have figured out a way to accomplish my goal but it's a bit messy so I was wondering if there's a better way that I'm not aware of. Here's the messy way I came up with:
var myListOfObject = (List<object>)((Dictionary<string, object>)JSON.parse(json))["$values"];
var myTypes = myListOfObject.ConvertAll(x => JSON.stringify(x).FromJson<MyType>());
I'm not necessarily looking for fewer lines of code because 2 isn't anything to complain about. I'm just hoping there is a way that doesn't require all the casting and parsing and rather can accept the json as is and get it back to the type it came from. Maybe there's even a parameter I can set to tell it to validate types during the deserialization since the full type names are in the json.

You should use the same serializer you used to serialize the payload to deserialize it. ServiceStack.Text uses __type to embed its type information, in a different schema so you wont be able to use ServiceStack.Text to automatically deserialize it into the embedded type.
This likely used JSON.NET which you should use instead to deserialize it, otherwise yeah you can use ServiceStack's JS Utils to deserialize arbitrary JSON as you're doing.

Related

How to extend the jsonschema validator?

For my project I need a new property for json schemas.
I named it "isPropertyOf" and basically what I want is that if I have this:
fruits = {
"banana": "yellow fruit",
"apple": "round fruit"
}
schema = {
"type": "object",
"properties": {
"fav_fruit": {
"type": "string",
"isPropertyOf": fruits
}
}
}
Then schema would validate only objects like {"fav_fruit":"banana"} or {"fav_fruit":"apple"}, but not {"fav_fruit":"salami"}
(I know that for this very example using an enum would make more sense, but assume "fruits" is also used for other stuff and I would rather avoid redundancy)
I read docs about this and figured I need to use jsonschema.validators.extend. I tried something like that:
def is_property_of_callable(validator_instance, property_value, instance, schema):
keys = [k for k in property_value]
return instance in keys
mapping = {"isPropertyOf": is_property_of_callable}
my_validator = jsonschema.validators.extend(jsonschema.Draft7Validator, mapping)
instance = {"fav_fruit": "tobacco"}
my_validator(schema).is_valid(instance)
I was ready to see something go wrong, but apparently the validator wasn't seeing any issue. I tried with an obviously wrong instance that even the standard validator of jsonschema wouldn't accept
my_validator(schema).is_valid({"fav_fruit": 0})
But apparently it looked ok to it.
I thought maybe the way I added this property was so broken that it was making the validator accept anything, so I tried a minimal case of validator extension:
minimal_validator = jsonschema.validators.extend(jsonschema.Draft7Validator, {})
minimal_validator(schema).is_valid(instance)
And this one is also happy with 0 being my favourite fruit.
What am I doing wrong here? How can I make that work?

how to get dictionary same order as same i am getting from json in objective c

i am parsing json and what i get set of dictionary but after parsing it will automatically change it order. i just need same order as same i am getting from json parsing.
NOTE: i want to make one functionality which depends on dictionary order, i don't want to make it manually. so it will not need to make it every-time to do.it will help to change dynamically in future
Example:
From Json:
Section:
{
category:{},
location:{},
vehicle_type:{},
mode_type:{}
}
after convert into NSDicationary:
Section:
{
vehicle_type:{}
category:{},
location:{},
mode_type:{}
}
Thanks
Order of key:value doesn't matter for JSON, as you can directly access value with the help of key string. An dictionary does not support indexing of elements, so you can't.
Dictionaries are not ordered collections. On other hand, arrays are.
Note, if you don't have access over the json format, you got no guarantees about the order of elements, if you don't have hardcoded logic in your app.
Having said that, let's take a deeper look into your case. It happens that you have one main object in your json that is Section. What is more, you have 4 ordered properties of this object that are of specific kind of their own: 0: category; 1: location; 2: vehicle_type; 3: mode_type. So here comes the good part: just change your json to look something like this:
Section:
[
{
title: "category",
value: {}
},
{
title: "location",
value: {}
},
{
title: "vehicle_type",
value: {}
},
{
title: "mode_type",
value: {}
}
]
Having this json, you just go through the Section ordered elements, check the title of the element, and create the corresponding Object. This way you can achieve what you are after.

f# - how to serialize option and DU as value or null (preferably with json.net)

How can i get my json from web api to format only value or null for Option types and Discriminated Unions preferably using Newtonsoft.
I am currently using Newtonsoft and only have to add this to web api for it to work:
config.Formatters.JsonFormatter.SerializerSettings <- new JsonSerializerSettings()
When i consume the data on my side, i can easily convert it back to an F# item using: JsonConvert.DeserializeObject<'a>(json)
The api will be consumed by NON .NET clients as well so i would like a more standard formatted json result.
I would like to to fix my issue, w/o having to add code or decorators to all of my records/DU in order for it to work. I have lots of records with lots of properties, some are Option.
ex (this is how DU is serializing):
// When value
"animal": {
"case": "Dog"
}
// When no value
"animal": null
This is what I need:
// When value
"animal": "Dog"
// When no value
"animal": null
This is how an Option type is serializing:
"DocumentInfo": {
"case": "Some",
"fields": [
{
"docId": "77fb9dd0-bfbe-42e0-9d29-d5b1f5f0a9f7",
"docType": "Monkey Business",
"docName": "mb.doc",
"docContent": "why cant it just give me the values?"
}
]
}
This is what I need:
"DocumentInfo": {
"docId": "77fb9dd0-bfbe-42e0-9d29-d5b1f5f0a9f7",
"docType": "Monkey Business",
"docName": "mb.doc",
"docContent": "why cant it just give me the values?"
}
Thank you :-)
You could try using Chiron. I haven't used it myself so I can't give you an extensive example, but https://neoeinstein.github.io/blog/2015/12-13-chiron-json-ducks-monads/index.html has some bits of sample code. (And see https://neoeinstein.github.io/blog/2016/04-02-chiron-computation-expressions/index.html as well for some nicer syntax). Basically, Chiron knows how to serialize and deserialize the basic F# types (strings, numbers, options, etc.) already, and you can teach it to serialize any other type by providing that type with two static methods, ToJson and FromJson:
static member ToJson (x:DocumentInfo) = json {
do! Json.write "docId" x.docId
do! Json.write "docType" x.docType
do! Json.write "docName" x.docName
do! Json.write "docContent" x.docContent
}
static member FromJson (_:DocumentInfo) = json {
let! i = Json.read "docId"
let! t = Json.read "docType"
let! n = Json.read "docName"
let! c = Json.read "docContent"
return { docId = i; docType = t; docName = n; docContent = c }
}
By providing those two static methods on your DocumentInfo type, Chiron will automatically know how to serialize a DocumentInfo option. At least, that's my understanding -- but the Chiron documentation is sadly lacking (by which I mean literally lacking: it hasn't been written yet), so I haven't really used it myself. So this may or may not be the answer you need, but hopefully it'll be of some help to you even if you don't end up using it.
I have found the solution that allows me to use Newtonsoft (JSON.NET), apply custom converters for my types where needed and not require any changes to my DU's or Records.
The short answer is, create a custom converter for Json.Net and use the Read/Write Json overrides:
type CustomDuConverter() =
inherit JsonConverter() (...)
Unfortunately the ones I have found online that were already created doesn't work as is for my needs listed above, but will with slight modification. A great example is to look at: https://gist.github.com/isaacabraham/ba679f285bfd15d2f53e
To apply your custom serializer in Web Api for every call, use:
config.Formatters.JsonFormatter.SerializerSettings.Converters.Add(new CustomDuConverter())
To deserialize use (example that will deserialize to DU):
JsonConvert.DeserializeObject<Animal>("Dog", customConverter)
ex:
type Animal = Dog | Cat
json:
"animal": "Dog"
This will allow you to create a clean Api for consumers and allow you to consume 3rd party Json data into your types that use Option, etc.

Working with dynamic/anonymous objects and JSON.NET

.NET 4.0; VS 2010.
We're consuming a web service that does not offer a WSDL. The data that is returned is not particularly complicated so we thought we would work with dynamic/anonymous types. Here is an example of the JSON returned from one of the service methods (this string has been verified with JSONLint):
[
{
"value": "AAA"
},
{
"value": "BBB"
},
{
"value": "CCC"
},
{
"value": "DDD"
},
{
"value": "EEE"
},
{
"value": "FFF"
}
]
Tried using:
dynamic respDyn = JsonConvert.DeserializeObject(jsonStringAbove);
In this case, no errors are thrown, but in trying to access the resp variable, the Visual Studio debugger reports "The name 'resp' does not exist in the current context".
Tried LINQ next:
var respLinq = JObject.Parse(jsonStringAbove);
Which results in a runtime error: Error reading JObject from JsonReader. Current JsonReader item is not an object: StartArray. Path '', line 1, position 1.
Found this article that recommended different parsing methods depending on the format of the JSON:
if (jsonStringAbove.StartsWith("["))
{
var arr = JArray.Parse(jsonStringAbove);
}
else
{
var obj = JObject.Parse(jsonStringAbove);
}
When var arr = JArray.Parse(jsonStringAbove); is hit, the debugger simply exists the method and returns to the calling procedure. No error is thrown. If the leading and trailing square brackets are removed, another run time error similar to the results in the second example is encountered.
So. Not sure where to turn at this point. Seems like what we're trying to do is very straightforward which make me think I'm missing something blatantly obvious.
Not sure why, but the solution to this was to declare my variables as fields within the class. Variables that were local to the methods I was working with simply did not work. Once declared as class-wide variables, the code behaved as expected. Very odd. I suspect that this problem may be specific to my VS environment and/or solution configuration as it does not appear to be occurring with anyone else. Lucky me.

JSON and VB.net

I've got a small utility I use to communicate with Yahoo's APIs. Their servers return all the responses in JSON.
Is there an easy way to parse this into its base form when you don't necessarily know what will be in the response?
{
"sessionId": "A.bpAsPs3RPYF0nUuAnCtuEUJMOmDDHbjZG5",
"primaryLoginId": "prometheussoft",
"displayInfo": {
"avatarPreference": "2",
"checksum": "-1484747745"
},
"server": "rcore1.messenger.yahooapis.com",
"notifyServer": "rproxy1.messenger.yahooapis.com",
"constants": {
"presenceSubscriptionsMaxPerRequest": 60
}
}
you can deserialize it to a dictionary with string parsing, any values that are objects can be done the same way with a nested dictionary.
However to get typing on the values you will need to at least know what is expected for each property