We are serialising an object to JSON which has a property that is an array of dynamic objects, e.g.:
public List<dynamic> Widgets { get; set; }
public string Name {get;set;}
The serialisation is set to use the built in camel case resolver, with the option ProcessDictionaryKeys set to true, as per advice from this post :
var contractResolver = new CamelCasePropertyNamesContractResolver();
contractResolver.NamingStrategy.ProcessDictionaryKeys = true;
jsonSerializerSettings.ContractResolver = contractResolver;
However the resultant JSON retains the pascal case (which is how the objects are stored in the database) for the entries in this field. All other properties get converted to camel case as expected.
Example output for the above:
{
name:"test",
widgets:[{Name:"Widget1",Description:"A nice widget"}]
}
So why does the naming strategy only apply to strongly typed C# objects and not these dynamic values?
I have verified the obvious things, i.e. ensured the serialisation settings are being applied.
Thanks to dbc for the help.
In case anyone else has the issue, the problem was that the underlying object was a JObject - for some reason I assumed it would be an ExpandoObject.
JSON.net will not respect the naming conventions for JObjects, they are serialised as-is so you must come up with some solution to manually convert the object keys.
I chose a custom object converter, as per this post: How to serialize a JObject the same way as an object with Json.NET?
Related
I have a JSON Schema, and a class library.
I am able to serialize this class, then convert back successfully to object.
To test it, I create a random object, serialize it.
Then convert to object and check its validity.
And deserialize it just to be sure about the values.
The code below works perfectly - but
I want to be absolutely sure that the class library represents the Json Schema.
Is there a way to achieve this? I found some online tools tries to create the class library from given schema, but none of them were so useful.
// Create random object.
MyObject myObject = new MyObject().CreateRandomMyObject();
// Serialize it.
string JSONObjectText = JsonConvert.SerializeObject(myObject);
// Check if schema is valid.
JSchema schema = JSchema.Parse(txtSchema.Value);
// Check if the serialized object is valid for schema.
JObject jsonObject = JObject.Parse(JSONObjectText);
IList<string> errorMessages;
bool valid = jsonObject.IsValid(schema, out errorMessages);
// Check if the serialized object can be deserialized.
MyObject myObjectReDeserialized = (MyObject)JsonConvert.DeserializeObject(JSONObjectText, typeof(MyObject), new JsonSerializerSettings() { MissingMemberHandling = MissingMemberHandling.Error });
A way to do test-oriented assertion of your mapping is to use FsCheck to generate plenty of random objects and then assert what you want to hold from them: in this case, that
their serialization is valid given the schema,
they can be deserialized back to the same object. (You should make sure you are using structural equality there.)
To be precise, such approach only checks that everything described by your objects is representable by the schema. You might want to do the other way also -- that every JSON that conforms to the schema is representable by your objects. Again, you can generate many possible JSONs conforming to the schema and check that
they can be deserialized to your objects,
reserialization of those objects gives you the same JSON you started with.
Beware though, this might not be practical: FsCheck probably don't have some nice, first-class support for JSON schema based generation out-of-the-box.
If the schema you have is going to change in the future, it would be really great to have a way to generate corresponding objects to have strong types even at the boundary of your application. Have you tried Swagger Codegen? Swagger describes it's endpoints using subset of JSON Schema. The corresponding tooling might help you.
I used the $type properties in Json for the deserialization of inherited objects (to choose the correct object type in which to deserialize at runtime)
I do this using :
config.Formatters.JsonFormatter.SerializerSettings = new JsonSerializerSettings{ TypeNameHandling = TypeNameHandling.Objects}
this line is in the WebApiConfig file.
It works fine but I can't figure out how to restrict the $type only to the webservices who actually needs it (I only need it for one PUT and one POST).
The $type is messing up the API results for the other webservices and I can't find some TypeNameHandling configuration nor some serialization option to avoid this.
Does anyone knows how to do that?
Cheers!
To enable type name handling on a nested object, you can attach [JsonProperty(ItemTypeNameHandling = TypeNameHandling.Objects)] to the containing property, like so:
public class RootObject
{
[JsonProperty(ItemTypeNameHandling = TypeNameHandling.Objects)]
public object Data { get; set; }
}
There's no builtin way to enable type name handling on a specific type, and so there's no builtin way to enable type name handling on the root object. Instead, you could use the EnableJsonTypeNameHandlingConverter from SignalR Typenamehandling if you need to do this.
Thanks for the help dbc. I had other issues during deserialization (using a OData.Delta object and the solution you proposed didn't actually fit completely the need.
I overcame the issue thanks to this post : Custom Json.NET serializer settings per type
to have the $type customization only for a few webservices.
I've successfully set up some classes that use TPH EF inheritance, MyBaseClass, MySubClass1, MySubClass2 etc.
When querying using Linq context.MyBaseClasses.Where(...), the objects returned all correctly use the subclass specified by the Discriminator field in the database. (So I might end up with a list containing a mix of objects of MySubClass1, or MySubClass2.)
However, when I pass these objects to a WPF application, via a JSON Web Api call, the objects received are all of MyBaseClass, rather than the correct sub class they started off at.
The object property they are returned via is of type public virtual List<MyBaseClass> MyThings, so I guess it makes sense that they all end up as this type, but I want to retain the correct sub class type for each object.
How do I achieve this? Do I need to force the EF Discriminator field to be sent along with all the other data somehow?
Edit
1.
At the client end, I'm now attempting to deserialize the JSON (including $type data) like so (with no luck, the items are still converted back to their base class)
HttpResponseMessage response = GetClient().GetAsync(url).Result;
if (response.IsSuccessStatusCode)
{
string jsonMessage;
using (Stream responseStream = response.Content.ReadAsStreamAsync().Result)
{
jsonMessage = new StreamReader(responseStream).ReadToEnd();
}
List<My.Domain.Models.MyBaseClass> thingsToReturn;
//new method
thingsToReturn = JsonConvert.DeserializeObject<List<My.Domain.Models.MyBaseClass>>(jsonMessage);
//previous method
//thingsToReturn = response.Content.ReadAsAsync<List<My.Domain.Models.MyBaseClass>>().Result;
return thingsToReturn;
}
2.
Following Anish's advice re SerializerSettings.TypeNameHandling, I've now got $type information appearing in my JSON, however this is of type System.Data.Entity.DynamicProxies.SubClass1_5E07A4CE2F037430DC7BFA00593.... is this OK for the client end to deserialize back into SubClass1 successfully?
This is a serialization concern.
You can customize Json.Net's serializer settings to include type information with your json objects.
Add this to your HttpConfiguration:
config.Formatters.JsonFormatter.SerializerSettings.TypeNameHandling = TypeNameHandling.Auto;
Where config is the HttpConfiguration instance that you use to configure and initialize Asp.Net WebApi.
This will tell Json.Net to add some type information to each json object that has type ambiguity. Such an object would look like this:
{
"$type":"MyProjectContainingMyTypes.MySubClass1, MyProjectContainingMyTypes",
"Name": "Tyrion Lannister",
"DisplayName": "The Imp",
"Traits": ["funny", "awesome", "clever"]
}
Json.Net will know how to deal with this when you deserialize this on the WPF side.
This should work, in your WPF app:
var things = JsonConvert.DeserializeObject<List<MyBaseClass>>(jsonString);
Then you can cast the objects in the things list to their respective derived types.
Of course, your WPF application will need to have a reference to the project where you define MyBaseClass and MySubClass1.
Edit
Thanks Anish, that's almost sorted it. I can see the correct $type data in the JSON, I'm just being a dunce, and I'm not sure how to get the WebApi response as a jsonString? At the minute I'm doing response.Content.ReadAsAsync>().Result; to auto deserialize the data.
In response to your comment, you can read the content as a string like this:
var jsonString = response.Content.ReadAsStringAsync().Result;
Edit 2
Anish, thanks so much for your input. As you can see, I've managed to get the JSON as a string now, but even using JsonConvert.DeserializeObject I'm still getting the same issue. Do you think it is (as I mention in Edit 2) to do with the $type being returned from the service incorrectly (as an EF proxy type)?
In response to your comment, yes you will not be able to deserialize the EF proxy type into the type you want. This issue needs to be resolved on the WebApi side.
The proxy classes are created to allow you to lazy load entities. Proxies are generally used represent referenced/nested entities. This allows the fetching of referenced entities from the database to be deferred until required, if required at all.
Here is a link to some documentation around lazy and eager loading entities with EF.
Solution
You want to hydrate the list of objects in your WebApi controller action and return it, this will tell EF to load the entities from the database and new up instances of your classes.
You have a few options here:
Option 1
Call ToList() on the query to hydrate the collection:
var result = (from t in dbContext.Things select t).ToList();
or
var result = dbContext.Things.ToList();
Naturally, you don't want to return an unbounded result set so add a range:
var result = (from t in dbContext.Things select t).Skip(0).Take(10).ToList();
or
var result = dbContext.Things.Skip(0).Take(10).ToList();
Bear in mind that with method you will have to explicitly hydrate nested objects like this:
var result = dbContext
.Things
.Include(t => t.SomePropertyThatRepresentsSomeNestedObject)
.Skip(0)
.Take(10)
.ToList();
Option 2
Turn off lazy loading for your DbContext.
Personally, I'd go with Option 1, I think it is better to know your entities and have control over when and what you hydrate.
Many, many thanks to Anish, who's answer set me off on the right track, along with this excellent article.
The steps I had to take to get the types of the inherited objects to pass through the web api service are as follows:
Server Side
The key things were to set the JsonFormatter Serializer TypeNameHandling setting to TypeNameHandling.Auto. This can be done in WebApiConfig.Register(), but it will then obviously add a $type property to all JSON objects returned by your web service calls, or, you can simply decorate the property of the object you need the $type for.
WebApiConfig Method
GlobalConfiguration.Configuration.Formatters.JsonFormatter.SerializerSettings.TypeNameHandling = Newtonsoft.Json.TypeNameHandling.Auto;
Property Decoration Method
[Newtonsoft.Json.JsonProperty(ItemTypeNameHandling = Newtonsoft.Json.TypeNameHandling.Auto)]
public virtual List<MyBaseClass> Things { get; set; }
To get the correct value in the $type property in the JSON, and not the EF proxy class name, I turned off the ProxyCreationEnabled property before performing the Linq query that returned the objects based on MyBaseClass.
dbContext.Configuration.ProxyCreationEnabled = false;
List<MyBaseClass> things = dbContext.MyBaseClasses.Include("This").Include("That").ToList();
Client Side
I had to add a JsonMediaTypeFormatter with SerializerSettings = { TypeNameHandling = TypeNameHandling.Auto } to the ReadAsAsync() call and then the (correctly typed) objects mapped to their sub class happily.
HttpResponseMessage response = GetClient().GetAsync(url).Result;
if (response.IsSuccessStatusCode)
{
//this formatter responds to the $type parameter passed in the JSON to allow us to correctly map object types
//https://kirmir.wordpress.com/2014/05/16/polymorphic-serialization-using-newton-json-net-in-httpcontent/
var formatter = new JsonMediaTypeFormatter
{
SerializerSettings = { TypeNameHandling = TypeNameHandling.Auto }
};
List<MyBaseClass> thingsToReturn;
thingsToReturn = response.Content.ReadAsAsync<List<MyBaseClass>>(new List<MediaTypeFormatter> { formatter }).Result;
return productTestsToReturn;
}
I am using Newtonsoft.Json to serialize/deserialize my C# object to/from JSON.
My C# object has a property of following type:
List<BaseClass> objects { get; set; }
This collection holds different child objects (e.g. - ChildClass1, ChildClass2).
Serializing to JSON works fine but while deserializing it creates objects of BaseClass in collection (which is obvious :)).
Is there a way I can create concrete child objects while deserializing?
I tried creating a custom converter by implementing CustomCreationConverter<BaseClass>. But the problem is overridden Create method gives me just the type and based on that I cannot decide which object to return (ChildClass1 or ChildClass2)
My JSON string has a Type property by which I can identify the child object to create.
Any help is highly appreciated.
You can use the TypeNameHandling option:
var settings = new JsonSerializerSettings { TypeNameHandling = TypeNameHandling.Auto }
JsonConvert.SerializeObject(myObject, Formatting.Indented, settings );
The TypeNameHandling option "Auto" ensures that type names are included in the serialized JSON
for subclasses. But watch out: these names become invalid when the classes or their namespaces are renamed!
I ma using Newtonsofts' Json.Net to serialize some and array of objects to json.
The objects have a common set of properties but also have Meta property which is a dictionary
During serialization I want the key value pairs to be added to my json object as if they where root level properties, like this...
{
id: 1,
name:'jeff',
food:'spinch',
spoon: 'ýes'
}
Not like this:
{
id: 1,
name:'jeff',
meta:{
food:'spinch',
spoon: 'ýes'
}
}
I have dug through JsonSerializerSettings but cant seem to spot where I can jump in and override???
You can do this by creating your own JsonConverter and then adding an attribute to the class you want to serialize
[JsonConverter(typeof(MyConverter))]
Example here -
http://www.lostechies.com/blogs/rhouston/archive/2008/02/25/a-custom-converter-for-json-net.aspx
If your dictionary is a string to object dictionary could can simply use the [JsonExtensionData] attribute:
[JsonExtensionData]
public Dictionary<string, object> Meta { get; set; }
See How to serialize a Dictionary as part of its parent object using Json.Net.
You could use the .Net DataContractJsonSerializer.
For custom serialization, see:
http://msdn.microsoft.com/en-us/library/system.runtime.serialization.idatacontractsurrogate.aspx
One advantage of using IDataContractSurrogate (compared to simply adding properties to your class for serialization) is that you don't have to mix actual properties and serialization properties together in the same class.
Another advantage (compared to having to do custom serialization against a property bag, ala KeyValuePairConverter) is that you only have to add attributes to properties on your classes (the actual type and the surrogate type) and you can write all your conversion/custom serialization code directly against those types. This keeps your code higher level, and lets the framework deal with the exact transport mechanism.