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

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.

Related

Avoid serialization of a property name in json.net

How to avoid a property name during serialization? Below an example
public class A {
public List<object> Values { get; set; }
public string Name { get; set; }
}
A a = new A();
a.Name = "Numbers"
a.Values = new List<object>();
a.Values.Add(1);
a.Values.Add(2);
a.Values.Add(3);
a.Values.Add(4);
JsonConvert.SerializeObject(new { a });
After serialization, result includes a property names "values"
{
"a": {
"values": [
1,
2,
3,
4
],
"name": "Numbers"
}
}
but, I need the following
{
"a": [
1,
2,
3,
4
],
"name": "Numbers"
}
Just serialize a.Values;
JsonConvert.SerializeObject(a.Values);
You have a couple mistakes in your code.
First, if you want this class:
public class A
{
public List<object> Values { get; set; }
public string Name { get; set; }
}
To serialize to this json:
{
"a": [
1,
2,
3,
4
],
"name": "Numbers"
}
You are gonna have a bad time. Just look at the structure, they are not 1-1.
You need to change your class, make sure you name it something meaningful (a class of a single letter is a really bad idea).
public class SomeClass
{
[JsonProperty("a")]
public List<object> Values { get; set; }
[JsonProperty("name")]
public string Name { get; set; }
}
You notice the [JsonProperty()] attribute above? That tells the serializer that this property should serialize with the defined name. That way you can have a meaningful property name ("Values") while in code, and still have the json serialize the way you want it to ("a").
The second problem is when you serialize you are creating a new anonymous object with a property of the class you instance you created. Which will again mess your structure up. Change your serialization code to just serialize the object instance:
string json = JsonConvert.SerializeObject(someInstanceOfYourClass);
My above changes should give you json that looks like this:
{
"a": [
1,
2,
3,
4
],
"name": "Numbers"
}
I have made a fiddle here that will demonstrate.

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.

Creating Non-Nullable Array Types With JSchemaGenerator

I am using Newtonsoft.Json.schema v1.0.6 and I am trying to generate JSchema for custom type that has an array property that is similar to this:
public class MyClass {
public List<MyChild> Children { get; set; }
}
public class MyChild {
public string MyProperty { get; set; }
}
The default JSchemaGenerator generates a JSchema similar to this:
{
"type": "object",
"properties": {
"MyChildren": {
"type": "array",
"items": {
"type": [
"object",
"null"
],
...
}
}
},
...
}
I do not want to accept null items in the MyChildren array. I have tried adding the [JsonProperty(Required = Required.Always)] attribute but it just makes the MyChildren property itself required and I cannot add the attribute to the MyChild class.
I figure I'm going to have to implement a custom JSchemaGenerationProvider but the JSchema.Items property is readonly.
How do I generate JSON schema for an object that has an array property that should not accept null values?
JSchema.Items is readonly but the schema inside it can be modified. Just set its Type to JSchemaType.String.

Automatically serialise child objects just from ids using JSON.NET

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; }
}

Parse Json Array with different of keyvalue

In one of my project i want to parse a JSON array with different key name. For Example
{ "details": [
{ "state": "myState1",
"place": [
{ "name": "placeName" } ] },
{ "state": "myState2",
"place": [
{ "name1": "placeName" } ] },
{ "state": "myState3",
"place": [
{ "name2": "placeName" } ] } }
So in this JSON please look at the place array. each time key like name1,name2,name3...,
.And also it is not necessary to get the same JSON at all the time. In some time only state1 or state1 and state3 and in some time state1 to state 50.
So how can i identify and parse exact data from this array
First of all your JSON is not well-formatted. You miss a closing square bracket ] before the last closing curly bracket }.
Then, you can't parse variable-name properties to a static class, but you can turn them into a dictionary. Here's an example of mapping classes that work with variable places:
public class Details
{
public string state { get; set; }
public List<Dictionary<string, string>> place { get; set; }
}
public class Wrap
{
public Details[] details { get; set; }
}
static void Main(string[] args)
{
string txt = File.ReadAllText("MyJSONFile.txt");
JavaScriptSerializer ser = new JavaScriptSerializer();
var data = ser.Deserialize<Wrap>(txt);
}
If also the place property will change name, I think the simplest way to parse it is to use the following, very loosely typed, class:
public class Wrap
{
public List<Dictionary<string,object>> details { get; set; }
}
where the object in the dictionary will be a string or a dictionary of properties according to the values in the JSON.

Categories

Resources