Automatically serialise child objects just from ids using JSON.NET - c#

When an object is serialized using the default JSON.NET serialization settings, child objects and their foreign keys are set separately as below:
{
"id": 1,
"postId": 22,
"tagId": 16,
"post": null,
"tag": null
}
Because I want the objects to play nice with client side JavaScript frameworks, I want the objects to be serialized more intelligently. Entity Framework already knows that the 'post' object is the object that is represented by 'postId', but how can I tell the serializer this?
I want this json to be serialized, even if the C# instance of the class being serialized has a null Post property.
{
"id": 1,
"post": {
"id": 22
},
"tag": {
"id": 16
}
}
I know that I can customize the serialization of each object using a JsonConverter but this involves writing a custom serializer for each type of object. I would prefer this type of serialization behaviour to be done automatically.
The above json represnts this C# class:
public class ExampleBlogObject
{
public int Id { get; set; }
public int PostId { get; set; }
public int TagId { get; set; }
[ForeignKey("PostId")]
public virtual Post Post { get; set; }
[ForeignKey("TagId")]
public virtual Tag Tag { get; set; }
}

Related

Need to inject values from parent object into child object when serializing

I'm setting up an API which dynamically advertises services as part of its response, letting the consumer know what else they can do with the object. I can't work out how to inject the parent's objects type and ID into the service URI.
I'm using attributes and custom JSON.NET IValueProviders to create the URIs (which is working fine for other dynamic examples), but in this case I need a property from outside the object.
Classes looks similar to:
public class Person
{
public Guid ID { get; set; }
public string Type { get; set; }
public string Name { get; set; }
[ObjectUri]
public string Uri { get; set; }
...
public IEnumerable<Service> Services { get; set; }
}
public class Service
{
public string ServiceName { get; set; }
[ServiceUri]
public string ServiceUri { get; set; }
}
I'm using a custom contract resolver to add the custom IValueProvider (ObjectUriValueProvider) which renders the object URI (which is obviously just using information from the same object).
However, because the contract resolver is operating at the level of the abstract model, there's no way to pass concrete values pertaining to the parent object to ServiceUriValueProvider.
Ideal output:
{
"id": "ae330dc8-0217-4c58-b64b-44a1c7ba4f46",
"type": "Person",
"name": "Fred",
"uri": "https://server/api/person/ae330dc8-0217-4c58-b64b-44a1c7ba4f46"
...
"services": [
{
"serviceName": "ListNotes",
"serviceUri": "https://server/api/notes/person/ae330dc8-0217-4c58-b64b-44a1c7ba4f46"
},
{
"serviceName": "ListContactDetails",
"serviceUri": "https://server/api/contacts/person/ae330dc8-0217-4c58-b64b-44a1c7ba4f46"
}
]
}
The actual results at the moment don't include the type and id being correctly populated into
{
"services": [
{
"serviceName": "ListNotes",
"serviceUri": "https://server/api/notes/{type}/{id}"
},{
"serviceName": "ListContactDetails",
"serviceUri": "https://server/api/contacts/{type}/{id}"
}
]
}

Json DeserializeObject into class with dynamic property

I'm trying to convert a string of JSON data into a C# class object. However I'm having an issue with a small part of the JSON which is dynamic in nature.
The part of the JSON is below:
"contact": [{
"comment": null,
"type": {
"id": "cell",
"name": "Example name"
},
"preferred": true,
"value": {
"country": "7",
"formatted": "+7 (702) 344-3423-3",
"number": "3498908",
"city": "702"
}
},
{
"type": {
"id": "email",
"name": "Email example"
},
"preferred": false,
"value": "name#mail.com"
}]
C# classes
public class Value
{
public string country { get; set; }
public string formatted { get; set; }
public string number { get; set; }
public string city { get; set; }
}
public class Type
{
public string id { get; set; }
public string name { get; set; }
}
public class Contact
{
public string comment { get; set; }
public Type type { get; set; }
public bool preferred { get; set; }
public string value { get; set; }
}
C# Code
Contact contact = JsonConvert.DeserializeObject<Contact>(result);
The format of "value" changes depending on the contact information. Is it possible to map value both as a string and also class Value.
Thanks for any help that can be provided.
You can literally just use dynamic, i.e.
public dynamic value { get; set; }
If it looks like an object, it will be materialized as a JObject, which can be used via the dynamic API, so .value.country will work, etc. If it looks like an integer, bool or string: it will be materialized as such. Arrays will also be handled suitably. So: you can check whether .value is string, etc. Note that this won't use your Value type, and doing so is more complex, but: meh; you get the data. You can always switch that out manually.
It will also behave like this if you use object instead of dynamic, but then it is harder to access the inner properties.
Try
Contact contact = JsonConvert.DeserializeObject<Contact>(result[0]);
As you can see in the JSON, it's
"contact": [
Indicating an array, currently you're just passing the entire array
Unless you're sure that the JSON comes always with the same structure, the best is to use a dynamic variable instead of deserialize it into a class.
If you like to work with classes you can always build your own on runtime using reflection. But that's like killing a fly with a cannon and you're probably won't need it, so just use a dynamic variable instead, it's the best to work with JSON strings.

How to store C# objects with dynamic properties in RavenDB?

I'm having problems when trying to save an object that has a dynamic property in RavenDB
The object I'm trying to save represents an order. The order contains a list of orderlines so imagine the following Order class:
public class Order {
public int Id { get; set; }
public List<Orderline> Orderlines { get; set; }
}
And the Orderline class being:
public class Orderline {
public Product Product { get; set; }
public int Quantity { get; set; }
public dynamic Attributes { get; set; }
}
The object I'm trying to save (I'll display it with JSON);
{
"Id": 0,
"Orderlines": [
{
"Product": {
"Id": 0,
"Name": "Some product"
},
"Quantity": 1,
"Attributes": {
"color": "Red"
}
}
]
}
Saving it does not throw any errors
RavenDB stores the Order object as
{
"Id": 0,
"Orderlines": [
{
"Product": {
"Id": 0,
"Name": "Some product"
},
"Quantity": 1,
"Attributes": {
"$type": "Newtonsoft.Json.Linq.JObject, Newtonsoft.Json",
"color": {
"$type": "Newtonsoft.Json.Linq.JValue, Newtonsoft.Json",
"$values": []
}
}
}
]
}
Note that the values property of Order.Orderlines[0].Attributes.color is not set...
When I try to serialize the object back to my C# Order object I get the following exception;
Unable to cast object of type
'Raven.Imports.Newtonsoft.Json.Utilities.CollectionWrapper`1[Newtonsoft.Json.Linq.JToken]'
to type 'Newtonsoft.Json.Linq.JValue'.
What am I doing wrong, how can I store this object in the RavenDB database and retrieve it?
What is the type that you are actually saving into attributes?
Typically you'll use something that is actually dynamic, like ExpandoObject
Storing the dynamic property with type 'dynamic' apparently wasn't enough. When I gave the Attributes property the ExpandoObject type, RavenDB stored the Attributes property as normal JSON (without $type and $values, so clean as desired)
When retrieving it back from the RavenDB database it deserializes back to an ExpandoObject object.
Make sure to cast the ExpandoObject property to a dynamic (e.g. 'as dynamic') when trying to display the property in a Razor view.

Deserializing JSON collection in C#

This is a JSON message I get from server (which I can't change). There might be many more objects (time / value) returned, but in this case there is only one. The format stays the same regardless.
{
"data": [
{
"time": "2014-12-12T13:52:43",
"value": 255.0
}
]
}
I'm trying to deserialize the JSON to a very simple C# object.
public class Dataentry {
public float Value { get; set; }
public DateTime Time { get; set; }
}
I've tried deserialization with Newtonsoft's JSON.Net and RestSharp libraries with no success. The following code doesn't work, but neither does anything else I've tried :-) I get no error -- just an empty object with default initial values.
var myObject = JsonConvert.DeserializeObject<Dataentry> (jsonString);
Since those libraries are not very intuitive or well documented in this kind of case, I'm lost. Is this kind of JSON impossible to deserialize? I really would like to use a ready-made library, so any help would be appreciated.
This is not working because your JSON is specifying a collection and you are trying to deseralize into one object. There are plenty of json to c# class generators you can paste json into to get an appropriate class definition(s) one such generator is located here
A more appropriate definition would be
public class Datum
{
public string time { get; set; }
public double value { get; set; }
}
public class RootObject
{
public List<Datum> data { get; set; }
}
Then deseralize as
var myObject = JsonConvert.DeserializeObject<RootObject> (jsonString);
I'd like add some extra explanetion to your question...
You write I'm trying to deserialize the JSON to a very simple C# object. - unfortunatelly this is not the complete truth. What you are trying is to deserialize a collection of a very simple C# objects. The indicator for this are the square brackets in your json:
{
"data": [
{
"time": "2014-12-12T13:52:43",
"value": 255.0
}
]
}
It means that there is a class with a property named data (it can ba mapped to some other name but for the sake of simplicity let's stick to this name) and that this property is a collection type. It can be one of any types that support the IEnumerable interface.
public class DataCollection
{
public DataItem[] data { get; set; }
//public List<DataItem> data { get; set; } // This would also work.
//public HashSet<DataItem> data { get; set; } // This would work too.
}
public class DataItem
{
public float value { get; set; }
public DateTime time { get; set; } // This would work because the time is in an ISO format I believe so json.net can parse it into DateTime.
}
The next step is to tell Json.Net how to deserialize it. Now when you know it's a complex data type you can use the type that describes the json structure for deserialization:
var dataCollection = JsonConvert.DeserializeObject<DataCollection>(jsonString);
If you didn't have the data property in you json string but something like this:
[
{
"time": "2014-12-12T13:52:43",
"value": 255.0
},
{
"time": "2016-12-12T13:52:43",
"value": 25.0
},
]
you could directly deserialize it as a collection:
var dataItems = JsonConvert.DeserializeObject<List<DataItem>>(jsonString);
or
var dataItems = JsonConvert.DeserializeObject<DataItem[]>(jsonString);
change your DateEntry binding Definition
public class ArrayData{
public DataEntry data {set; get;}
}
public class DataEntry {
public float Value { get; set; }
public DateTime Time { get; set; }
}
in your method now you can received an ArraData Object
be careful with datetime string values sent for correct binding

JavaScriptSerializer and MVC - struggling with JSON

I've been trying to figure out why some of my tests haven't been working (TDD) and managed to track it down to serialization of a class, but I'm not sure why it's not working. There are two flavours, a simple version and a more complex version, the slightly more complicated one involves having an array of values within the Parameter.Value.
The simple version, I've got a class that can be serailzied using the JavaScriptSerializer (I'm assuming this is how MVC works when it generates JSON). The structure it produces looks like this:
{
"Name": "TestQuery",
"QueryId": 1,
"Parameters": [
{
"Name": "MyString",
"DataType": 0,
"Value": "A String",
"IsArray": false
}],
"Sql": "SELECT * FROM Queries"
}
There are 3 C# classes Query, ParameterCollection (which is a KeyedCollection<String, Parameter>) and a Parameter. All of these are marked up with DataContract/DataMember attributes and serialize via the DataContractSerializer without any problem.
The JavaScriptSerializer however, serializes the object correctly to the JSON above, but upon deserialization I have no Parameters, they just seem to get missed off.
Does anyone have any idea why these fails, and what I might be able to do to fix it?
Why KeyedCollection<String, Parameter>? You have an array, not dictionary, so your JSON should match the following structure:
public class Query
{
public int QueryId { get; set; }
public string Name { get; set; }
public string Sql { get; set; }
public Parameter[] Parameters { get; set; }
}
public class Parameter
{
public string Name { get; set; }
public int DataType { get; set; }
public string Value { get; set; }
public bool IsArray { get; set; }
}
and then you will be able to deserialize it without any problems:
var serializer = new JavaScriptSerializer();
var json = #"
{
""Name"": ""TestQuery"",
""QueryId"": 1,
""Parameters"": [
{
""Name"": ""MyString"",
""DataType"": 0,
""Value"": ""A String"",
""IsArray"": false
}],
""Sql"": ""SELECT * FROM Queries""
}";
var query = serializer.Deserialize<Query>(json);
Also you can get rid of [Data*] attributes from your view models, they are not used by the JavaScriptSerializer class.

Categories

Resources