I'm using Json.NET in my WCF data service.
Here's my class (simplified):
[DataContract]
public class Component
{
public Component()
{
// I'm doing some magic here.
}
}
How can I deserialize that class without invoking a constructor using JsonConvert.DeserializeObject?
Sorry if not clear, feel free to ask questions.
A constructor is always invoked. I usually have two constructors. One for serialization (the default constructor) and one for all "regular" code:
[DataContract]
public class Component
{
// for JSON.NET
protected Component()
{
}
public Component(allMandatoryFieldsHere)
{
// I'm doing some magic here.
}
}
In that way I can also make sure that the dev specify all information which are required.
However, I do not really recommend that you use anything but DTO's when transfering information since it's otherwise possible to circumvent the encapsulation of your objects (anyone could initialize any field with any value). Well. If you use anything but anemic models.
Using FormatterServices.GetSafeUninitializedObject is imho therefore an ugly workaround, since no one can tell that you create all objects in an unintialized way. Constructor initialization is there for a reason. It's better that the classes can tell that it's OK to not call the real constructor by providing a "serialization" constructor as I suggested.
You could create a class that inherits from CustomCreationConverter
and use FormatterServices.GetSafeUninitializedObject to create your
object. It skips calling the constructor.
More about CustomCreationConverter here.
Placing
[JsonObject(MemberSerialization.Fields)] on a class will make Json.NET use
FormatterServices.GetSafeUninitializedObject by default (although
Fields mode will also serialize public/private fields rather than
public properties which you may not want).
Move the logic you don't want run outside of the default constructor.
Others already mentioned the second constructor, but using 2 attributes: [JsonConstructor] and [Obsolete] you can do much better than leaving it up to humans to remember which one to call.
public ChatMessage()
{
MessageID = ApplicationState.GetNextChatMessageID(); // An expensive call that uses up an otherwise free ID from a limited set and does disk access in the process.
}
[JsonConstructor] // This forces JsonSerializer to call it instead of the default.
[Obsolete("Call the default constructor. This is only for JSONserializer", true)] // To make sure that calling this from your code directly will generate a compiler error. JSONserializer can still call it because it does it via reflection.
public ChatMessage(bool DO_NOT_CALL_THIS)
{
}
[JsonConstructor] forces JsonSerializer to call it instead of the default.
[Obsolete("...", true)] Makes sure that calling this from your code directly will generate a compiler error. JSONserializer can still call it because it does it via reflection.
The best option to avoid constructor calls on deserialization is to create special contract resolver that overrides creator function for all classes without constructor marked with JsonConstructor attribute. This way you still can force JSON.NET to call constructor if you really need it, but all other classes will be created much like in standard DataContract serializers in .NET. Here is the code:
/// <summary>
/// Special contract resolver to create objects bypassing constructor call.
/// </summary>
public class NoConstructorCreationContractResolver : DefaultContractResolver
{
/// <summary>
/// Creates a <see cref="T:Newtonsoft.Json.Serialization.JsonObjectContract"/> for the given type.
/// </summary>
/// <param name="objectType">Type of the object.</param>
/// <returns>
/// A <see cref="T:Newtonsoft.Json.Serialization.JsonObjectContract"/> for the given type.
/// </returns>
protected override JsonObjectContract CreateObjectContract(Type objectType)
{
// prepare contract using default resolver
var objectContract = base.CreateObjectContract(objectType);
// if type has constructor marked with JsonConstructor attribute or can't be instantiated, return default contract
if (objectContract.OverrideCreator != null || objectContract.CreatedType.IsInterface || objectContract.CreatedType.IsAbstract)
return objectContract;
// prepare function to check that specified constructor parameter corresponds to non writable property on a type
Func<JsonProperty, bool> isParameterForNonWritableProperty =
parameter =>
{
var propertyForParameter =
objectContract.Properties.FirstOrDefault(property => property.PropertyName == parameter.PropertyName);
if (propertyForParameter == null)
return false;
return !propertyForParameter.Writable;
};
// if type has parameterized constructor and any of constructor parameters corresponds to non writable property, return default contract
// this is needed to handle special cases for types that can be initialized only via constructor, i.e. Tuple<>
if (objectContract.CreatorParameters.Any(parameter => isParameterForNonWritableProperty(parameter)))
return objectContract;
// override default creation method to create object without constructor call
objectContract.DefaultCreatorNonPublic = false;
objectContract.DefaultCreator = () => FormatterServices.GetSafeUninitializedObject(objectContract.CreatedType);
return objectContract;
}
}
All you need is simply set this contract resolver in serializer settings before deserialization.
Update on readonly fields and get-only properties
A readonly field can be deserialized if it has a JsonProperty attribute applied.
A get-only property can also be deserialized if it's backing field has a JsonProperty attribute applied.
Since C# 7.3 it's possible to apply attributes to compiler-generated backing fields of auto-properties.
Leveraging this we could do something like this:
public class SampleClass
{
[JsonProperty("Field1")]
private readonly string _field1 = "Field1Value";
[JsonProperty("Property1")]
private string _property1BackingField = "Property1Value";
[JsonIgnore]
public string Property1 => _property1BackingField;
[field: JsonProperty("Property2")]
[JsonIgnore]
public string Property2 { get; } = "Property2Value";
}
const string json = "{\"Field1\":\"NEW-Field1Value\",\"Property1\":\"NEW-Property1Value\",\"Property2\":\"NEW-Property2Value\"}";
var serializerSettings = new JsonSerializerSettings
{
ContractResolver = new DefaultContractResolver
{
// this settings is needed to work with compiler-generated backing fields
SerializeCompilerGeneratedMembers = true
}
};
var deserializedSample = JsonConvert.DeserializeObject<SampleClass>(json, serializerSettings);
If you need to do this in older C# version or have no control over attributes, you could override CreateProperty() method of DefaultContractResolver with something like this:
protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization)
{
var jsonProperty = base.CreateProperty(member, memberSerialization);
if (jsonProperty.Writable == false)
{
// this uses compiler implementation details and may not work for all cases
// better to use smarter approach like in BackingFieldResolver from Mono.Reflection library
var fieldInfo = jsonProperty.DeclaringType.GetField($"<{jsonProperty.PropertyName}>k__BackingField",
BindingFlags.NonPublic | BindingFlags.Instance);
if (fieldInfo != null)
{
jsonProperty.ValueProvider = new ReflectionValueProvider(fieldInfo);
jsonProperty.Writable = true;
}
}
return jsonProperty;
}
Related
I'm deserializing a bunch of C# readonly structures (which have their constructors marked by [JsonConstructor]), and I'm trying to fail early if any JSON that I receive is malformed.
Unfortunately, if there is a naming discrepancy between the constructor parameter and the input JSON, the parameter just gets assigned a default value. Is there a way that I could get an exception instead, so these defaults don't accidentally "pollute" the rest of my business logic? I have tried playing with various JsonSerializerSettings but to no avail.
Simplified example:
public readonly struct Foo {
[JsonConstructor]
public Foo(long wrong) {
FooField = wrong;
}
public readonly long FooField;
}
public void JsonConstructorParameterTest() {
// The Foo constructor parameter name ("wrong") doesn't match the JSON property name ("FooField").
var foo = JsonConvert.DeserializeObject<Foo>("{\"FooField\":42}");
// The foo.FooField is now 0.
// How can we cause the above to throw an exception instead of just assigning 0 to Foo.FooField?
}
The above can be fixed by renaming wrong into fooField, but I'd like to know that before 0 has already been committed to my database.
The contract resolver from this answer to JSON.net should not use default values for constructor parameters, should use default for properties almost does what you want, however it has a noted restriction:
This only works if there is a corresponding property. There doesn't appear to be a straightforward way to mark a constructor parameter with no corresponding property as required.
Since marking an "unmatched" constructor parameter as required doesn't seem to work (demo fiddle #1 here) you can modify the contract resolver from that answer to throw an exception during contract construction if an unmatched constructor parameter is found.
The following contract resolver does this:
public class ConstructorParametersRequiredContractResolver : DefaultContractResolver
{
protected override JsonProperty CreatePropertyFromConstructorParameter(JsonProperty matchingMemberProperty, ParameterInfo parameterInfo)
{
// All constructor parameters are required to have some matching member.
if (matchingMemberProperty == null)
throw new JsonSerializationException(string.Format("No matching member for constructor parameter \"{0}\" of type \"{1}\".", parameterInfo, parameterInfo.Member.DeclaringType));
var property = base.CreatePropertyFromConstructorParameter(matchingMemberProperty, parameterInfo);
if (property != null && matchingMemberProperty != null)
{
if (!matchingMemberProperty.IsRequiredSpecified) // If the member is already explicitly marked with some Required attribute, don't override it.
{
Required required;
if (matchingMemberProperty.PropertyType != null && (matchingMemberProperty.PropertyType.IsValueType && Nullable.GetUnderlyingType(matchingMemberProperty.PropertyType) == null))
{
required = Required.Always;
}
else
{
required = Required.AllowNull;
}
// It turns out to be necessary to mark the original matchingMemberProperty as required.
property.Required = matchingMemberProperty.Required = required;
}
}
return property;
}
}
To use it, construct the resolver:
static IContractResolver resolver = new ConstructorParametersRequiredContractResolver();
And unit test as follows:
var settings = new JsonSerializerSettings
{
ContractResolver = resolver,
};
JsonConvert.DeserializeObject<Foo>("{\"FooField\":42}", settings);
Note you may want to cache and reuse the contract resolver for best performance.
Demo fiddle #2 here.
I have a class:
public class MyClass
{
public MyEnum Foo{ get; set; }
}
During serialization i'd like to change the output from
{
"Foo": 1
}
to
{
"Foo": "EnumName"
}
I've tried creating an IValueProvider but hit dead ends every way I go. (My scenario is a bit more complicated than stated; I need to find a way to do this entirely within the IContractResolver.)
You could create a custom ContractResolver inheriting from DefaultContractResolver that automatically applies StringEnumConverter to every contract for an enum or nullable enum:
public class StringEnumContractResolver : DefaultContractResolver
{
readonly StringEnumConverter converter;
public StringEnumContractResolver() : this(true, false) { }
public StringEnumContractResolver(bool allowIntegerValue, bool camelCaseText)
{
this.converter = new StringEnumConverter { AllowIntegerValues = allowIntegerValue, CamelCaseText = camelCaseText };
}
protected override JsonPrimitiveContract CreatePrimitiveContract(Type objectType)
{
var contract = base.CreatePrimitiveContract(objectType);
var type = Nullable.GetUnderlyingType(contract.UnderlyingType) ?? contract.UnderlyingType;
if (type.IsEnum && contract.Converter == null)
contract.Converter = converter;
return contract;
}
}
Notes:
If the enum type already has a JsonConverter applied, that is kept in preference to the default StringEnumConverter.
Adding the converter to the JsonPrimitiveContract for the enum itself, rather than to every JsonProperty for members that return the enum, ensures that the converter is applied to enums in collections and dictionaries.
The IValueProvider merely provides methods to get and set values and thus is less convenient to this purpose than the converter. You would need to perform a nested serialization and deserialization of the enum value as a JSON string inside it, but it isn't designed for this and so doesn't have access to the JSON reader, writer, or serializer. In addition, there is no value provider for dictionary values or collection items that are enums.
You may want to cache the contract resolver for best performance as explained here.
Sample .Net fiddle.
Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 6 years ago.
Improve this question
Is there a way to tell JSON.net that when it attempts to deserialize using a constructor (if there is no default constructor), that it should NOT assign default value to constructor parameters and that it should only call a constructor if every constructor parameter is represented in the JSON string? This same serializer SHOULD use default values when calling property/field setters, the rule is only scoped to constructors. None of the enum values here seem to be appropriate: http://www.newtonsoft.com/json/help/html/T_Newtonsoft_Json_DefaultValueHandling.htm
The solution should NOT rely on applying any attributes to the types being deserialized.
for example, the json string "{}" will deserialize to an object of type Dog by setting the Dog's age to 0 (the default value for an int). I'd like to a generalized, not-attribute-based solution to prevent this from happening. In this case, {"age":4} would work because age is specified in the JSON string and corresponds to the constructor parameter.
public class Dog
{
public Dog(int age)
{
this.Age = age;
}
public int Age { get; }
}
However, if Dog is specified as such, then "{}" should deserialize to a Dog with Age == 0, because the Dog is not being created using a constructor.
public class Dog
{
public int Age { get; set; }
}
As to "why would you want to do this"... Objects with constructors are typically qualitatively different than POCOs as it relates to their properties. Using a constructor to store property values instead of settable properties on a POCO typically means that you want to validate/constrain the property values. So it's reasonable not to allow deserialization with default values in the presence of constructor(s).
When Json.NET encounters an object without a parameterless constructor but with a parameterized constructor, it will call that constructor to create the object, matching the JSON property names to the constructor arguments by name using reflection via a case-insensitive best match algorithm. I.e. a property whose name also appears in the constructor will be set via the constructor call, not the set method (even if there is one).
Thus, you can mark a constructor argument as required by marking the equivalent property as required:
public class Dog
{
public Dog(int age)
{
this.Age = age;
}
[JsonProperty(Required = Required.Always)]
public int Age { get; }
}
Now JsonConvert.DeserializeObject<Dog>(jsonString) will throw when the "age" property is missing.
Since this is something you always want, you can create a custom contract resolver inheriting from DefaultContractResolver or CamelCasePropertyNamesContractResolver that marks properties passed to the constructor as required automatically, without the need for attributes:
public class ConstructorParametersRequiredContractResolver : DefaultContractResolver
{
protected override JsonProperty CreatePropertyFromConstructorParameter(JsonProperty matchingMemberProperty, ParameterInfo parameterInfo)
{
var property = base.CreatePropertyFromConstructorParameter(matchingMemberProperty, parameterInfo);
if (property != null && matchingMemberProperty != null)
{
var required = matchingMemberProperty.Required;
// If the member is already explicitly marked with some Required attribute, don't override it.
// In Json.NET 12.0.2 and later you can use matchingMemberProperty.IsRequiredSpecified to check to see if Required is explicitly specified.
// if (!matchingMemberProperty.IsRequiredSpecified)
if (required == Required.Default)
{
if (matchingMemberProperty.PropertyType != null && (matchingMemberProperty.PropertyType.IsValueType && Nullable.GetUnderlyingType(matchingMemberProperty.PropertyType) == null))
{
required = Required.Always;
}
else
{
required = Required.AllowNull;
}
// It turns out to be necessary to mark the original matchingMemberProperty as required.
property.Required = matchingMemberProperty.Required = required;
}
}
return property;
}
}
Then construct an instance of the resolver:
static IContractResolver requiredResolver = new ConstructorParametersRequiredContractResolver();
And use it as follows:
var settings = new JsonSerializerSettings { ContractResolver = requiredResolver };
JsonConvert.DeserializeObject<T>(jsonString, settings)
Now deserialization will throw if the "age" property is missing from the JSON.
Notes:
This only works if there is a corresponding property. There doesn't appear to be a straightforward way to mark a constructor parameter with no corresponding property as required.
Newtonsoft recommends that you cache and reuse the contract resolver for best performance.
Demo fiddle here.
This question already has answers here:
Serialize Property, but Do Not Deserialize Property in Json.Net
(2 answers)
Closed 6 years ago.
I have a scenario with a class defined as below:
class MyObject
{
public DataDictionary MyObjectData { get; set; }
public bool ShouldSerializeMyObjectData() { return true; }
public bool ShouldDeserializeMyObjectData() { return false; }
}
When I attempt to serialize/deserialize that class with JSON.net, it takes the ShouldSerialize into account, but not the ShouldDeserialize.
According to the documentation, both should work the same way I guess. Is there something particular I should know? More generally, how should I deal with scenarios where I want to serialize a property but not deserialize it?
I'm using Json.NET 8.0 if that matters.
Thanks for your help.
The short answer to your question is, automatically checking for ShouldDeserialize{PropertyName}() is not currently implemented even though ShouldSerialize{PropertyName}() is. A longer answer and workaround follow.
The class JsonProperty is used internally by Json.NET to define a contract for how to map a JSON property to a .NET member or constructor parameter. It has two predicate properties, ShouldSerialize and ShouldDeserialize that, when non-null, prevent a property from being serialized and deserialized, respectively. Initializing each JsonProperty is the job of the ContractResolver. For each property {PropertyName}, Json.NET's default contract resolver automatically checks for the presence of a public bool ShouldSerialize{PropertyName}() method. If such a method exists, it adds a call to it in the ShouldSerialize predicate, thereby suppressing serialization when the method returns false. This was implemented because controlling property serialization via a method ShouldSerialize{PropertyName}() is a standard pattern supported by, e.g., XmlSerializer. For more background see the relevant Json.NET release notes.
For example, in the following class, serialization of MyObjectData will be suppressed unless MyObjectData.Count > 0:
class MyObject
{
public DataDictionary MyObjectData { get; set; }
public bool ShouldSerializeMyObjectData() { return MyObjectData != null && MyObjectData.Count > 0; }
}
JsonProperty.ShouldDeserialize, however, it is never set by the default contract resolver. This may be due to the fact that there is no standard pattern for deserialization equivalent to ShouldSerialize{PropertyName}() and so Newtonsoft never had any requests to implement such a pattern. Nevertheless, as you have noticed, infrastructure to support such a pattern exists, and so applications can create custom contract resolvers that do just that. In fact, Json.NET has an example of such a contract resolver in its own test suite:
public class ShouldDeserializeContractResolver : DefaultContractResolver
{
public static new readonly ShouldDeserializeContractResolver Instance = new ShouldDeserializeContractResolver();
protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization)
{
JsonProperty property = base.CreateProperty(member, memberSerialization);
MethodInfo shouldDeserializeMethodInfo = member.DeclaringType.GetMethod("ShouldDeserialize" + member.Name);
if (shouldDeserializeMethodInfo != null)
{
property.ShouldDeserialize = o => { return (bool)shouldDeserializeMethodInfo.Invoke(o, null); };
}
return property;
}
}
public class ShouldDeserializeTestClass
{
[JsonExtensionData]
public IDictionary<string, JToken> ExtensionData { get; set; }
public bool HasName { get; set; }
public string Name { get; set; }
public bool ShouldDeserializeName()
{
return HasName;
}
}
If you want to conditionally suppress deserialization of properties even when present in the JSON, you may use this contract resolver.
Notes:
If you do use a custom contract resolver, you should cache and reuse it for best performance.
JsonProperty.ShouldDeserialize is called before the property value is deserialized. If it returns true, the property is skipped, with no ability to examine the contents of the property. Thus it cannot be used to implement custom filtering based on that value.
A JSON object is defined by the JSON standard as an unordered set of name/value pairs. Thus a ShouldDeserialize method that assumes that other properties have already been read in may be brittle.
Instead, if you want to skip deserialization of one property based on the value of another, consider using an [OnDeserialized] callback and clearing the unwanted value there, after all properties have been deserialized.
I have a type like this:
class Foo<T>
{
public string Text { get; set; }
public T Nested { get; set; }
public static string ToJson(Foo<T> foo) { [...] }
}
ToJson serializes a Foo<Bar> instance to JSON in a way that is impossible to achieve by tweaking JsConfig. Also, ToJson relies on ServiceStack.Text to serialize Nested, which can be an instance of Foo<Baz>.
Unfortunately, the way JsConfig is implemented implies that there will be a JsConfig<T> set of static variables for Foo<Bar> and other for Foo<Baz>. Also, AFAIK, ServiceStack.Text offers no way to configure JSON serialization for open generic types (i.e.: something like JsConfig.Add(typeof(Foo<>), config)). I tried to solve this issue by creating this static constructor for Foo<T>:
static Foo() {
JsConfig<Foo<T>>.RawSerializeFn = ToJson;
}
This doesn't work all the time. It depends on the order the static constructors are invoked by the runtime. Apparently, ServiceStack.Text caches serializers functions and sometimes is doing it before the static constructor is called depending on the order operations are invoked in the API, so:
var outer = new Foo<Baz> { Text = "text" };
outer.ToJson(); // OK, because Nested is null
var inner = new Foo<Bar>();
inner.ToJson(); // OK, because JsConfig<Foo<Bar>>.RawSerializeFn is Foo<T>.ToJson
outer.Nested = inner;
outer.ToJson(); // NOT OK, because SS.Text uses the default serializer for Foo<T>, not Foo<T>.ToJson
I can't set all the serializers in JsConfig<Foo<T>> beforehand because T can be virtually any type, even other generic types.
Is it possible to define custom serialization routines for open generic types (that can be nested) in ServiceStack.Text?
I solved for this in my own way with a wrapper and a custom deserializer. I created a base type for all of my abstract types. That base type tells the system which type it is:
public class SetSettingItemBase
{
public string Key { get; set; }
public string ValueType { get; set; }
}
So the base is essentially the metadata -- the setting key + the value type. The object DTO, then, simply extends it by adding the actual value:
public class SetSettingItem : SetSettingItemBase
{
public object Value { get; set; }
}
Note that it's just an object. This is the DTO, not my actual object. I can cast it later, or convert it to a real/generic type after serialization.
My custom serialization then is:
JsConfig<SetSettingItem>.RawDeserializeFn = str =>
{
var baseSettings = str.FromJson<SetSettingItemBase>();
var ret = baseSettings.MapTo<SetSettingItem>();
if(true) // actual condition removed here... unimportant to the example
{
var dataType = Constants.KnownSettingsTypes[baseSettings.ValueType];
var method = typeof(JsonExtensions).GetMethod("JsonTo").MakeGenericMethod(dataType);
var key = "Value";
var parsed = JsonObject.Parse(str);
if(parsed.Object(key) == null)
key = "value";
ret.Value = method.Invoke(null, new object[] { parsed, key });
}
return ret;
};
This method first deserializes to the simple base. So the Value passed in from the DTO is ignored when deserializing baseSettings. I then call MapTo to prepare the actual SetSettingItem DTO. MapTo is just a wrapper around AutoMapper. You could just as easily use SS's built in mapper here.
For security, I have a set list of types that I allow as settings. Example:
KnownSettingsTypes.Add("string", typeof(string));
KnownSettingsTypes.Add("int", typeof(int));
KnownSettingsTypes.Add("nullableint", typeof(int?));
KnownSettingsTypes.Add("nullablepercentage", typeof(double?));
KnownSettingsTypes.Add("feegrid", typeof(FeeGrid));
After that, I use reflection to get the JsonTo method, passing in the generic type parameter dynamically from the KnownSettingsTypes dictionary.
And then finishing it all up, I parse the object using the generic JsonObject.Parse method and then looking for the Value or value (depending on case sensitivity) and explicitly convert that JsonObject using the dynamic method I created earlier.
The end result is I can pass in settings of all different types here as a part of my DTOs.
This served my purposes for the time being, but looking at the example I could see it improving in two ways:
After parsing, I could convert my SetSettingItem to a SettingItem<T> so I could use it as a strongly-typed object in my code. Remember, this example is just for the DTOs to get it across the wire.
Instead of requiring the person to pass in the type for me to check against, I could check against the setting Key to know which type it is supposed to be and parse accordingly. In my example, even if I check against the master list of settings and their types, I'd still probably require them to pass in the type just as a precaution and throw an exception if they didn't match.