I use Manatee.Json.JsonValue a whole lot, for instance in a case I have now, where I have a property of type object. This object property can contain both literals or complex types.
When the property value contains a complex type of JsonValue, it is serialized as an empty object! Is it possible to avoid this, such that other property values are serialized, while object property values of type JsonValue are just copied?
Here is an example with Manatee.Json.13.0.2:
public class TestObject
{
public object Property { get; set; }
}
[TestClass]
public class TestClass
{
[TestMethod]
public void Test()
{
var testObject = new TestObject
{
Property = new JsonValue("testString")
};
JsonValue expected = new JsonValue(
new JsonObject
{
["Property"] = "testString",
}
);
var serializer = new Manatee.Json.Serialization.JsonSerializer();
JsonValue actual = serializer.Serialize(testObject);
var expectedString = expected.ToString();
/// expectedString "{\"Property\":\"testString\"}" string
var actualString = actual.ToString();
/// actualString "{\"Property\":{}}" string
Assert.AreNotEqual(expectedString, actualString);
}
}
Anyone have any idea how to do this?
So, I've come to find a solution that seems to cover my use case.
I have managed to create a simple JsonSerializer that copies values. Upon serialization, the goal is to go from the source object to a JsonValue target. If the source value is either a JsonValue, a JsonObject or a JsonArray instance, the serialization method returns a JsonValue. Other types throws an ArgumentOutOfRangeException.
Upon deserialization, the goal is to go from a JsonValue and back to the requested type. If the requested type is a JsonValue, the current JsonValue are returned. If the requested type is a JsonObject, either the current JsonValue.Object are returned, or a new JsonObject if JsonValue.Object is null. Same goes for JsonArray: JsonValue.Array ?? new JsonArray. Other requested types returns null;
The serializer must be registered with the SerializerFactory.AddSerializer(mySerializer) somewhere. For me it is typically in Global.asax.cs and in a MSTest [AssemblyInitialize()] method.
Here is my implementation at this point:
public class JsonValueSerializer : ISerializer
{
public bool ShouldMaintainReferences => false;
private Type[] HandledTypes = {
typeof(JsonValue),
typeof(JsonObject),
typeof(JsonArray)
};
public bool Handles(SerializationContextBase context)
{
return HandledTypes.Contains(context.InferredType);
}
public JsonValue Serialize(SerializationContext context)
{
if (context.Source is JsonValue jsonValue)
return jsonValue;
else if (context.Source is JsonObject jsonObject)
return new JsonValue(jsonObject);
else if (context.Source is JsonArray jsonArray)
return new JsonValue(jsonArray);
else
throw new ArgumentOutOfRangeException();
}
public object Deserialize(DeserializationContext context)
{
if (context.RequestedType == typeof(JsonValue))
{
return context.LocalValue;
}
else if (context.RequestedType == typeof(JsonObject))
{
return context.LocalValue.Object ?? new JsonObject();
}
else if (context.RequestedType == typeof(JsonArray))
{
return context.LocalValue.Array ?? new JsonArray();
}
return null!;
}
}
Weakness of this implementation:
Deserialization can be done with serializer.Deserialize<JsonObject>(myJsonValue). A problem with this implementation, is that when I have a complex class with an object property, and that property contains a JsonObject (or a JsonArray), it works to serialize the complex type into JsonValue, but upon deserialization, the previous JsonObject would be deserialized into a JsonValue of JsonValueType.Object. This is different from the original JsonObject, since JsonValue can contain a JsonObject, but JsonObject is a type in its own right.
Without additional mechanisms, it would be impossible to know if the JsonValue should be kept or if it should be turned back into a JsonObject or a JsonArray. One could decide that on deserialization, all JsonValue.Object would be constantly set to a JsonObject type, but that would be wrong when it initially was a JsonValue of JsonValueType.Object (same for JsonArray). Another approach could maybe be to let JsonObject get a "$type" parameter with the information, but that wouldn't work with JsonArray. I have no fix for this behaviour.
Related
I find it difficult to force the deserialize operation to actually fail if the data doesn't match exactly what's expected for the output class.
class ContainerClass {
string SomeString { get; set; } // <-- not nullable
}
Json file :
[
{
"SomeString": null, // <-- null
}
]
Deserialize function :
using JsonTextReader reader = new JsonTextReader(file); // <-- the file I got from my controller.
var serializer = Newtonsoft.Json.JsonSerializer.Create(); // or new Serializer, whatever
serializer.MissingMemberHandling = MissingMemberHandling.Error;
return serializer.Deserialize<Collection<RegisterImportItem>>(reader);
I want the deserialize to fail if the string has a null value.
The code above succeeds silently and places a null value in the non-nullable field. The horror!
I'd like to achive that by configuring the serializer (as in : I don't want to add a decorator above the field itself ).
Long things short: I want all non-nullable fields to fail if the value is null, no matter what.
JSON.NET was written well before nullable reference types were a thing. The best way to do this is to use the JsonProperty attribute.
Annotate the property with JsonProperty
[JsonProperty(Required = Required.DisallowNull)]
your json is array but you are trying to deserialize object, try this code
var json=#"[
{
""SomeString"": null, // <-- null
""JustString"": ""test""
}
]";
var test = JsonConvert.DeserializeObject<ContainerClass[]>(json);
and fix the class by adding an accessor
public class ContainerClass {
public string SomeString { get; set; }
public string JustString { get; set; }
}
I think I found the answer here : Json.NET require all properties on deserialization
public class RequireObjectPropertiesContractResolver : DefaultContractResolver
{
protected override JsonObjectContract CreateObjectContract(Type objectType)
{
var contract = base.CreateObjectContract(objectType);
contract.ItemRequired = Required.Always;
return contract;
}
}
var settings = new JsonSerializerSettings { ContractResolver = new RequireObjectPropertiesContractResolver() };
var serializer = Newtonsoft.Json.JsonSerializer.Create(settings);
EDIT: That's NOT the right answer. Now it forbids all the null fields, even the ones that are nullable in the Container class.
There is no way of achieving this on all fields at once.
The only way is with decorators on individual fields.
I am getting a big nested json object from an external api. I want to make sure all fields are populated in that json object. Is there any libray available to do that? Newtonsoft.Json has JToken class which checks if the Json's schema is valid or not but i don't find any method to check if all the fields inside json object are filled.
Scenario : I am building an api which gathers information about a person or entity. there are numerous sources of information. I need to continue searching for the data until the required object is full. So first call goes to api1, gets some data, checks if object is full. If object is not full then goes to api2 and so on. So the call returns after the object is full. One key point is that the required object schema is not static.
I could deserialize it to a POCO and loop through each nested object but i am looking for a better solution.
Any suggestion is highly appreciated.
If I understood you correctly, you have some complex JSON object, with a set of required and not-required properties.
I see here three solutions:
You've already mentioned JSON schema validation. Here is one of the implementations: Json.NET Schema.
Create a POCO object and mark all properties with corresponding Required/Not-Required attributes. In this case, you'll get exceptions if a json-string doesn't contain any mandatory data. For example, how it's done in terms of Json.NET's JsonPropertyAttribute:
[JsonObject]
public class PocoObject
{
[JsonProperty("$schema", Required = Required.Default, NullValueHandling = NullValueHandling.Ignore)]
public string Schema { get; set; }
[JsonProperty("name", Required = Required.Always)]
public string Name { get; set; }
[JsonProperty("properties", Required = Required.Always)]
public MorePropertiesObject Properties { get; set; }
}
As a bonus, you can add your custom attributes, methods, converters, etc
Deserialize raw json into a Dictionary-like structure and validate it with your own hands-written validator. Something like:
try
{
var jo = JObject.Parse(jsonString);
Contract.Assert(!string.IsNullOrEmpty(jo["root"]["prop1"].ToString()));
Contract.Assert(!string.IsNullOrEmpty(jo["root"]["prop2"].ToString()));
}
catch (JsonReaderException) { }
catch (JsonSerializationException) { }
Provided code samples are for mentioned by you Newtonsoft.Json
If you have a JSON string and simply want to check whether any property value or array item are null, you can parse to a JToken, recursively descend the JToken hierarchy with JContainer.DescendantsAndSelf(), and check each JValue for being null using the following extension method:
public static partial class JsonExtensions
{
public static bool AnyNull(this JToken rootNode)
{
if (rootNode == null)
return true;
// You might consider using some of the other checks from JsonExtensions.IsNullOrEmpty()
// from https://stackoverflow.com/questions/24066400/checking-for-empty-null-jtoken-in-a-jobject
return rootNode.DescendantsAndSelf()
.OfType<JValue>()
.Any(n => n.Type == JTokenType.Null);
}
public static IEnumerable<JToken> DescendantsAndSelf(this JToken rootNode)
{
if (rootNode == null)
return Enumerable.Empty<JToken>();
var container = rootNode as JContainer;
if (container != null)
return container.DescendantsAndSelf();
else
return new[] { rootNode };
}
}
And then do:
var root = JToken.Parse(jsonString);
var anyNull = root.AnyNull();
If you just want to check for null property values (i.e. null values in an array are OK) you can use the following extension method:
public static partial class JsonExtensions
{
public static bool AnyNullPropertyValues(this JToken rootNode)
{
if (rootNode == null)
return true;
return rootNode.DescendantsAndSelf()
.OfType<JProperty>()
.Any(p => p.Value == null || p.Value.Type == JTokenType.Null);
}
}
(It isn't entirely clear from your question which you want.)
Sample .Net fiddle.
When serializing an object, I have a List<T> property where T is an abstract type which I'd like to serialize naturally. However, when deserializing the object, I want/need to manually deserialize this abstract list. I'm doing the latter part with a custom JsonConverter which looks at a property on each item
in the list and then deserializes it to the correct type and puts it in the list.
But I also need to deserialize the rest of the object, without doing it property-by-property. Pseudo-code follows.
MyObject
class MyObject {
public Guid Id;
public string Name;
public List<MyAbstractType> Things;
}
MyObjectConverter
class MyObjectConverter : JsonConverter {
public override object ReadJson(reader, ..., serializer) {
// Line below will fail because the serializer will attempt to deserlalize the list property.
var instance = serializer.Deserialize(reader);
var rawJson = JObject.Load(reader); // Ignore reading from an already-read reader.
// Now loop-over and deserialize each thing in the list/array.
foreach (var item in rawJson.Value<JArray>(nameof(MyObject.Things))) {
var type = item.Value<string>(nameof(MyAbstractType.Type));
MyAbstractType thing;
// Create the proper type.
if (type == ThingTypes.A) {
thing = item.ToObject(typeof(ConcreteTypeA));
}
else if (type == ThingTypes.B) {
thing = item.ToObject(typeof(ConcreteTypeB));
}
// Add the thing.
instance.Things.Add(thing);
}
return instance;
}
}
To recap, I want to manually handle the deserialization of Things, but allow them to naturally serialize.
I've got a class which has been serialized into JSON, and which I'm trying to deserialize into an object.
e.g.
public class ContentItemViewModel
{
public string CssClass { get; set; }
public MyCustomClass PropertyB { get; set; }
}
the simple property (CssClass) will deserialize with:
var contentItemViewModels = ser.Deserialize<ContentItemViewModel>(contentItems);
But PropertyB gets an error...
We added a JavaScriptConverter:
ser.RegisterConverters(new List<JavaScriptConverter>{ publishedStatusResolver});
But when we added 'MyCustomClass' as a 'SupportedType', the Deserialize method was never called. However when we have ContentItemViewModel as the SupportedType, then Deserialize is called.
We've got a current solution which looks something like this:
class ContentItemViewModelConverter : JavaScriptConverter
{
public override object Deserialize(IDictionary<string, object> dictionary, Type type, JavaScriptSerializer serializer)
{
var cssClass = GetString(dictionary, "cssClass"); //I'm ommitting the GetString method in this example...
var propertyB= GetString(dictionary, "propertyB");
return new ContentItemViewModel{ CssClass = cssClass ,
PropertyB = new MyCustomClass(propertyB)}
}
public override IDictionary<string, object> Serialize(object obj, JavaScriptSerializer serializer)
{
throw new Exception("Only does the Deserialize");
}
public override IEnumerable<Type> SupportedTypes
{
get
{
return new List<Type>
{
typeof(ContentItemViewModel)
};
}
}
}
But we'd prefer a simpler solution of only deserializing MyCustomClass, as there are a number of other fields which are on the ViewModel, and it seems a waste to have to edit this converter every time we change/add a property....
Is there a way to Deserialize JUST PropertyB of type MyCustomClass?
Thanks for your help!
Have you considered using DatacontractJsonSerializer
[DataContract]
public class MyCustomClass
{
[DataMember]
public string foobar { get; set; }
}
[DataContract]
public class ContentItemViewModel
{
[DataMember]
public string CssClass { get; set; }
[DataMember]
public MyCustomClass PropertyB { get; set; }
}
class Program
{
static void Main(string[] args)
{
ContentItemViewModel model = new ContentItemViewModel();
model.CssClass = "StackOver";
model.PropertyB = new MyCustomClass();
model.PropertyB.foobar = "Flow";
//Create a stream to serialize the object to.
MemoryStream ms = new MemoryStream();
// Serializer the User object to the stream.
DataContractJsonSerializer ser = new DataContractJsonSerializer(typeof(ContentItemViewModel));
ser.WriteObject(ms, model);
byte[] json = ms.ToArray();
ms.Close();
string s= Encoding.UTF8.GetString(json, 0, json.Length);
Console.ReadLine();
}
}
Add all possible classes to DatacontractJsonSerializer.KnownTypes if MyCustomClass has derivations.
For whatever it may be worth after all this time, but I stumbled over the same problem and the solution is that the Deserializer hasn't got a clue about the classes you are deserializing unless you give him the necessary information.
On the top level, it knows the type from the type parameter of Deserialize<>(). That's why your converter for ContentItemViewModel works. For nested objects, it needs __type properties and a JavaScriptTypeResolver.
var ser = new JavaScriptSerializer(new SimpleTypeResolver());
ser.RegisterConverters(myconverters);
MyClass myObject = new MyClass();
string json = ser.Serialize(myObject);
// set a breakpoint here to see what has happened
ser.Deserialize<MyClass>(json);
A TypeResolver adds a __type property to each serialized object. You can write a custom type resolver that uses short names. In this sample, I use the SimpleTypeResolver from .net that "simply" stores the fully qualified type name as __type. When deserializing, the JavaScriptDeserializer finds __type and asks the TypeResolver for the correct type. Then it knows a type and can call a registered JavaScriptConverter.Deserialize method.
Without a TypeResolver, objects are deserialized to a Dictionary because JavaScriptSerializer doesn't have any type information.
If you can't provide a __type property in your json string, I think you'll need to deserialize to Dictionary first and then add a "guessing-step" that interprets the fields to find the right type. Then, you can use the ConvertToType method of JavaScriptSerializer to copy the dictionary into the object's fields and properties.
If you need to use the JavaScriptSerializer that is provides by ASP.NET and can't create your own, consider this section from the .ctor help of JavaScriptSerializer:
The instance of JavaScriptSerializer that is used by the asynchronous communication layer for invoking Web services from client script uses a special type resolver. This type resolver restricts the types that can be deserialized to those defined in the Web service’s method signature, or the ones that have the GenerateScriptTypeAttribute applied. You cannot modify this built-in type resolver programmatically.
Perhaps the GenerateScriptType Attribute can help you. But I don't know what kind of __type Properties are be needed here.
am new to Json so a little green.
I have a Rest Based Service that returns a json string;
{"treeNode":[{"id":"U-2905","pid":"R","userId":"2905"},
{"id":"U-2905","pid":"R","userId":"2905"}]}
I have been playing with the Json.net and trying to Deserialize the string into Objects etc.
I wrote an extention method to help.
public static T DeserializeFromJSON<T>(this Stream jsonStream, Type objectType)
{
T result;
using (StreamReader reader = new StreamReader(jsonStream))
{
JsonSerializer serializer = new JsonSerializer();
try
{
result = (T)serializer.Deserialize(reader, objectType);
}
catch (Exception e)
{
throw;
}
}
return result;
}
I was expecting an array of treeNode[] objects. But its seems that I can only deserialize correctly if treeNode[] property of another object.
public class treeNode
{
public string id { get; set; }
public string pid { get; set; }
public string userId { get; set; }
}
I there a way to to just get an straight array from the deserialization ?
Cheers
You could use an anonymous class:
T DeserializeJson<T>(string s, T templateObj) {
return JsonConvert.Deserialize<T>(s);
}
and then in your code:
return DeserializeJson(jsonString, new { treeNode = new MyObject[0] }).treeNode;
Unfortunately JSON does not support Type Information while serializing, its pure Object Dictionary rather then full Class Data. You will have to write some sort of extension to extend behaviour of JSON serializer and deserializer in order to support proper type marshelling.
Giving root type will map the object graph correctly if the types expected are exact and not derived types.
For example if I have property as array of base class and my real value can contain derived child classes of any type. JSON does not support it completely but web service (SOAP) allows you to serialize objects with dynamic typing.