Deserializing json - mapping single property with no direct json match - c#

I am trying to deserialize an existing JSON structure to into an object composed of a set of models. The naming in these models are not consistent and I was specifically asked to not change them (renaming, adding attributes, etc).
So, given this Json text (just a small sample):
{
"parameter": {
"alarms": [
{
"id": 1,
"name": "alarm1",
"type": 5,
"min": 0,
"max": 2
}],
"setting-active": true,
"setting-oneRun": true
}
}
would need to be mapped into these models:
public class Alarm
{
public int AlarmId { get; set; }
public string AlarmName { get; set; }
public AlarmType RbcType { get; set; }
public int MinimumTolerated { get; set; }
public int MaximumTolerated { get; set; }
}
public class Setting
{
public bool Active { get; set; }
public bool OneRun { get; set; }
}
public class Parameter
{
public List<Alarm> Alarms { get; set; }
public Setting ParameterSetting { get; set; }
}
So far, im writing a class that extends DefaultContractResolver and overrides maps property names.
MyCustomResolver so far:
public class MyCustomResolver : DefaultContractResolver
{
private Dictionary<string, string>? _propertyMappings;
protected override IList<JsonProperty> CreateProperties(Type type, MemberSerialization memberSerialization)
{
//ModelMappings is a static class that will return a dictionary with mappings per ObjType being deserialized
_propertyMappings = ModelMappings.GetMapping(type);
return base.CreateProperties(type, memberSerialization);
}
protected override string ResolvePropertyName(string propertyName)
{
if (_propertyMappings != null)
{
_propertyMappings.TryGetValue(propertyName, out string? resolvedName);
return resolvedName ?? base.ResolvePropertyName(propertyName);
}
return base.ResolvePropertyName(propertyName);
}
}
Code that Im using to deserialize:
var settings = new JsonSerializerSettings();
settings.DateFormatString = "YYYY-MM-DD";
settings.ContractResolver = new MyCustomResolver();
Parameter p = JsonConvert.DeserializeObject<Parameter>(jsonString, settings);
So I reached a point I need to somehow map the properties in Parameter to values located in the prev json node ("setting-active", "setting-oneRun"). I need to tell the deserializer where these values are.
Can this be done using an extension of DefaultContractResolver ?
I appreciate any tips pointing in the right direction

You can apply ModelMappings.GetMapping(objectType) in DefaultContractResolver.CreateObjectContract():
public class MyCustomResolver : DefaultContractResolver
{
protected override JsonObjectContract CreateObjectContract(Type objectType)
{
var contract = base.CreateObjectContract(objectType);
var overrides = ModelMappings.GetMapping(objectType);
if (overrides != null)
{
foreach (var property in contract.Properties.Concat(contract.CreatorParameters))
{
if (property.UnderlyingName != null && overrides.TryGetValue(property.UnderlyingName, out var name))
property.PropertyName = name;
}
}
return contract;
}
}
Notes:
By applying the mappings in CreateObjectContract() you can remap both property names and creator parameter names.
Since the contract resolver is designed to resolve contracts for all types, storing a single private Dictionary<string, string>? _propertyMappings; doesn't really make sense.
Unlike your previous question, your current question shows properties from a nested c# object ParameterSetting getting percolated up to the parent object Parameter. Since a custom contract resolver is designed to generate the contract for a single type, it isn't suited to restructuring data between types. Instead, consider using a DTO or converter + DTO in such situations:
public class ParameterConverter : JsonConverter<Parameter>
{
record ParameterDTO(List<Alarm> alarms, [property: JsonProperty("setting-active")] bool? Active, [property: JsonProperty("setting-oneRun")] bool? OneRun);
public override void WriteJson(JsonWriter writer, Parameter? value, JsonSerializer serializer)
{
var dto = new ParameterDTO(value!.Alarms, value.ParameterSetting?.Active, value.ParameterSetting?.OneRun);
serializer.Serialize(writer, dto);
}
public override Parameter? ReadJson(JsonReader reader, Type objectType, Parameter? existingValue, bool hasExistingValue, JsonSerializer serializer)
{
var dto = serializer.Deserialize<ParameterDTO>(reader);
if (dto == null)
return null;
existingValue ??= new ();
existingValue.Alarms = dto.alarms;
if (dto.Active != null || dto.OneRun != null)
existingValue.ParameterSetting = new () { Active = dto.Active.GetValueOrDefault(), OneRun = dto.OneRun.GetValueOrDefault() };
return existingValue;
}
}
If your "real" model is too complex to define a DTO, you could create a JsonConverter<Paramater> that (de)serializes the JSON into an intermediate JToken hierarchy, then restructures that. See e.g. this answer to Can I serialize nested properties to my class in one operation with Json.net?.
In some cases, the custom naming of your properties is just camel casing. To camel case property names without the need for explicit overrides, set MyCustomResolver.NamingStrategy to CamelCaseNamingStrategy e.g. as follows:
var settings = new JsonSerializerSettings
{
DateFormatString = "YYYY-MM-DD",
// Use CamelCaseNamingStrategy since many properties in the JSON are just camel-cased.
ContractResolver = new MyCustomResolver { NamingStrategy = new CamelCaseNamingStrategy() },
Converters = { new ParameterConverter() },
};
Demo fiddle here.

I think that the best way to "KEEP IT SIMPLE", you need to define an object that has exactly the properties of the json. Then you can use a library like "Automapper" to define rules of mapping between the "json object" and the "business object".

Related

C# custom json serialization converter to set all default value of an object to null

I have a nested object that looks like:
public record Options
{
public BatterySettings BatterySettings { get; init; } = new();
public LogSettings LogSettings { get; init; } = new();
}
public record LogSettings
{
public string SourceName { get; init; } = "Default";
}
public record BatterySettings
{
public int BatteryLevel { get; init; } = 5;
public string BatteryHealth { get; init; } = "Normal";
public BatteryLocations BatteryLocation { get; init; } = BatteryLocations.North;
}
public enum BatteryLocations
{
North,
South
}
After initializing the object and setting some properties i.e.:
var opt = new Options
{
BatterySettings = new BatterySettings {
BatteryLevel = 10,
BatteryHealth = "Low"
}
}
I would like to get a JSON string that represents this object opt while having all the default value set to null i.e. in this above example, the resulting opt JSON string would look like:
{
"BatterySettings":{
"BatteryLevel":10,
"BatteryHealth":"Low",
"BatteryLocation":null
},
"LogSettings":{
"SourceName":null
}
}
Is there a built-in way in .NET to do such a thing?
Edit 1: the built-in way of utilizing the null serialization settings would not work since the object Options has non-null default values for its properties and sub-object properties.
It seems that a custom converter would need to be implemented here though I have trouble figuring out the correct approach to this due to having to compare default values with the object's current value for every given nodes
In this post I will show you how can you serialize the BatterySettings
if the property value is the same as the auto-generated property's default value then serialize it as null
if the property value is different than the auto-generated property's default value then serialize it as it is
In your particular case the default values of your auto-generated properties may or may not be the same as the run-time defaults. So, we can't use the default operator. To solve this problem I suggest the following "trick"
public record BatterySettings
{
private const int BatteryLevelDefault = 5;
public int BatteryLevel { get; init; } = BatteryLevelDefault;
private const string BatteryHealthDefault = "Normal";
public string BatteryHealth { get; init; } = BatteryHealthDefault;
private const BatteryLocations BatteryLocationDefault = BatteryLocations.North;
public BatteryLocations BatteryLocation { get; init; } = BatteryLocationDefault;
}
So, the "trick" is that we have a dedicated constant field for each property to store the default values. I've marked them as private so other class can't access them only via reflection.
Now let's see how the converter looks like for this data structure.
(Please note that this is not production-ready code. It is just for demonstration purposes.)
class BatterySettingsConverter : JsonConverter<BatterySettings>
{
private readonly PropertyInfo[] Properties = typeof(BatterySettings).GetProperties();
private readonly FieldInfo[] ConstFields = typeof(BatterySettings).GetFields(BindingFlags.NonPublic | BindingFlags.Static);
public override BatterySettings? ReadJson(JsonReader reader, Type objectType, BatterySettings? existingValue, bool hasExistingValue, JsonSerializer serializer)
=> throw new NotImplementedException();
public override void WriteJson(JsonWriter writer, BatterySettings? value, JsonSerializer serializer)
{
var result = new JObject();
foreach (PropertyInfo prop in Properties)
{
var defaultValueField = ConstFields.FirstOrDefault(fi => fi.Name.StartsWith(prop.Name));
if (!prop.CanRead || defaultValueField == null)
continue;
object propVal = prop.GetValue(value);
object defaultVal = defaultValueField.GetValue(value);
JToken serializeVal = !propVal.Equals(defaultVal) ? JToken.FromObject(propVal, serializer) : null;
result.Add(prop.Name, serializeVal);
}
result.WriteTo(writer);
}
}
I've stored on the class-level the properties and the fields of the BatterySettings record
Inside the WriteJson, first I create an accumulator object (result)
Then I iterate through the properties and try to find the matching field
If the related field is not exist / the property does not have a getter then I simply skip it
This logic could be and should be tailored to your needs
I retrieve the property's actual value and the constant field's value
Based on the result of equality check I decide what to serialize
At the very end I ask json.net to perform the serialization of the accumulator object
After I have decorated the BatterySettings with the following attribute [JsonConverter(typeof(BatterySettingsConverter))] then I can perform some testing
var x = new BatterySettings();
var json = JsonConvert.SerializeObject(x);
//{"BatteryLevel":null,"BatteryHealth":null,"BatteryLocation":null}
var y = new BatterySettings() { BatteryHealth = "A"};
json = JsonConvert.SerializeObject(y);
//{"BatteryLevel":null,"BatteryHealth":"A","BatteryLocation":null}
var z = new BatterySettings() { BatteryLocation = BatteryLocation.South};
json = JsonConvert.SerializeObject(z);
//{"BatteryLevel":null,"BatteryHealth":null,"BatteryLocation":1}
You can apply the same logic for the rest of your domain classes/records/sturcts.
In case of Json.Net there is a NullValueHandling settings under the JsonSerializerSettings where you can control the null values' serialization.
var settings new JsonSerializerSettings
{
NullValueHandling = NullValueHandling.Include
};
string json = JsonConvert.SerializeObject(opt, Formatting.Indented, settings);
In case of System.Text.Json there is a WhenWritingNull settings (please be aware that IgnoreNullValues is obsolete) under the JsonSerializerOptions where you can control the null values' serialization.
var options = new JsonSerializerOptions()
{
DefaultIgnoreCondition = JsonIgnoreCondition.Never
};
string json = JsonSerializer.Serialize<Options>(opt,options);

Custom JsonConvertor that also serializes it's value minus one of it's properties

I am having trouble with the requirement to serialize an object in a specific way whereby the object id value becomes the key and the rest of the object forms the value.
Simplified class to be serialized:
[JsonConverter(typeof(FieldTypeConvertor))]
public class FieldType {
public string Id { get; set; }
public string Condition { get; set; }
public string FieldType { get; set; }
public string Label { get; set; }
public string Options { get; set; }
}
Here is my JsonConvertor WriteJson method:
public override void WriteJson(JsonWriter writer, UmbracoFormFieldDto value, JsonSerializer serializer)
{
var props = value.GetType().GetProperties();
var idProp = props.FirstOrDefault(p => p.Name.Equals("id", StringComparison.OrdinalIgnoreCase));
var key = idProp.GetValue(value, null).ToString();
var newObj = JsonConvert.SerializeObject(value, new JsonSerializerSettings()
{ ContractResolver = new IgnorePropertiesResolver(new[] { "id" }) });
var container = new JObject { { key, newObj } };
container.WriteTo(writer);
}
I get why I end up with a StackOverflow but do not know how to avoid it in order generate the output I need which is the following:
"idValueFromOriginalObj": {
"condition": "propValue",
"fieldype": "propValue",
"label": "propValue",
"options": "propValue"
}
Essentially, the value of id in the original object becomes the key in the serialized object and the rest of the original object properties form the value.
Your problem is that, inside JsonConverter.ReadJson(), you are attempting to recursively serialize your value object, but since the converter is applied directly to the type using [JsonConverter(typeof(TConverter))], you are getting a stack overflow.
There are several options to disable a converter for recursive serialization; JSON.Net throws StackOverflowException when using [JsonConvert()] details some of them. However, since you are already using a custom contract resolver IgnorePropertiesResolver to ignore properties named "id", you might enhance the resolver to also ignore converters of type FieldTypeConvertor. The following should do the trick:
public class IgnorePropertiesResolver : DefaultContractResolver
{
readonly HashSet<string> propertiesToIgnore;
readonly HashSet<Type> converterTypesToIgnore;
public IgnorePropertiesResolver(IEnumerable<string> propertiesToIgnore, IEnumerable<Type> converterTypesToIgnore) : base() =>
(this.propertiesToIgnore, this.converterTypesToIgnore) =
((propertiesToIgnore ?? throw new ArgumentNullException()).ToHashSet(StringComparer.OrdinalIgnoreCase),
(converterTypesToIgnore ?? throw new ArgumentNullException()).ToHashSet());
protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization)
{
var property = base.CreateProperty(member, memberSerialization);
if (propertiesToIgnore.Contains(member.Name))
property.Ignored = true;
if (property.Converter != null && converterTypesToIgnore.Contains(property.Converter.GetType()))
property.Converter = null;
return property;
}
protected override JsonContract CreateContract(Type objectType)
{
var contract = base.CreateContract(objectType);
if (contract.Converter != null && converterTypesToIgnore.Contains(contract.Converter.GetType()))
contract.Converter = null;
return contract;
}
};
Then modify FieldTypeConvertor as follows:
public sealed class FieldTypeConvertor : JsonConverter<UmbracoFormFieldDto>
{
static readonly IContractResolver innerResolver = new IgnorePropertiesResolver(new [] { "id" }, new [] { typeof(FieldTypeConvertor) })
{
NamingStrategy = new CamelCaseNamingStrategy(),
};
public override void WriteJson(JsonWriter writer, UmbracoFormFieldDto value, JsonSerializer serializer)
{
var props = value.GetType().GetProperties();
var idProp = props.FirstOrDefault(p => p.Name.Equals("id", StringComparison.OrdinalIgnoreCase));
var key = idProp.GetValue(value, null).ToString();
writer.WriteStartObject();
writer.WritePropertyName(key);
JsonSerializer.CreateDefault(new JsonSerializerSettings { ContractResolver = innerResolver }).Serialize(writer, value);
writer.WriteEndObject();
}
public override UmbracoFormFieldDto ReadJson(JsonReader reader, Type objectType, UmbracoFormFieldDto existingValue, bool hasExistingValue, JsonSerializer serializer) => throw new NotImplementedException();
}
And your model will be serialized as required:
{
"idValueFromOriginalObj": {
"condition": "propValue",
"fieldType": "propValue",
"label": "propValue",
"options": "propValue"
}
}
Notes:
Newtonsoft recommends you cache the contract resolver for best performance.
You should inherit from DefaultContractResolver instead of CamelCasePropertyNamesContractResolver for reasons explained in Json.Net: Html Helper Method not regenerating.
For performance reasons, I eliminated the intermediate serialization to JObject and instead serialized directly to the incoming JsonWriter.
Demo fiddle here.

Custom attribute handling in Json.Net

My goal is to serialize properties that don't have any attributes and properties which have a specific custom attribute.
For the following class:
public class Msg
{
public long Id { get; set; }
[CustomAttributeA]
public string Text { get; set; }
[CustomAttributeB]
public string Status { get; set; }
}
When I call a method Serialize(object, CustomAttributeA), I want to have the following output:
{
"Id" : someId,
"Text" : "some text"
}
And when I call Serialize(object, CustomAttributeB), I want to have following:
{
"Id" : someId,
"Status" : "some status"
}
I have read that it's possible to achieve this by creating a custom ContractResolver, but in this case must I create two separate contract resolvers?
You do not need two separate resolvers to achieve your goal. Just make the custom ContractResolver generic, where the type parameter represents the attribute you are looking for when serializing.
For example:
public class CustomResolver<T> : DefaultContractResolver where T : Attribute
{
protected override IList<JsonProperty> CreateProperties(Type type, MemberSerialization memberSerialization)
{
IList<JsonProperty> list = base.CreateProperties(type, memberSerialization);
foreach (JsonProperty prop in list)
{
PropertyInfo pi = type.GetProperty(prop.UnderlyingName);
if (pi != null)
{
// if the property has any attribute other than
// the specific one we are seeking, don't serialize it
if (pi.GetCustomAttributes().Any() &&
pi.GetCustomAttribute<T>() == null)
{
prop.ShouldSerialize = obj => false;
}
}
}
return list;
}
}
Then, you can make a helper method to create the resolver and serialize your object:
public static string Serialize<T>(object obj) where T : Attribute
{
JsonSerializerSettings settings = new JsonSerializerSettings
{
ContractResolver = new CustomResolver<T>(),
Formatting = Formatting.Indented
};
return JsonConvert.SerializeObject(obj, settings);
}
When you want to serialize, call the helper like this:
string json = Serialize<CustomAttributeA>(msg);
Demo fiddle: https://dotnetfiddle.net/bRHbLy

id field resolution when using JObject.FromObject

I have a family of custom Json Converters. They work like this:
public override void WriteJson(Newtonsoft.Json.JsonWriter writer, object value, Newtonsoft.Json.JsonSerializer serializer) {
JObject jo = JObject.FromObject(value);
// do my own stuff to the JObject here -- basically adding a property. The value of the property depends on the specific converter being used.
jo.WriteTo(writer, this);
}
The problem with this is that the id field of the JObject is always 1. Not good. So I tried using an inner serializer to get the id field:
private JsonSerializer _InnerSerializer {get;set;}
private JsonSerializer InnerSerializer {
get {
if (_InnerSerializer == null) {
_InnerSerializer = new JsonSerializer();
}
return _InnerSerializer;
}
}
public override void WriteJson(Newtonsoft.Json.JsonWriter writer, object value, Newtonsoft.Json.JsonSerializer serializer) {
JsonSerializer inner = this.InnerSerializer;
jo = JObject.FromObject(value, inner);
//my stuff here
jo.WriteTo(writer, this);
}
That gives a different id each time, even if it hits the same object twice. What I really want is to use Json's usual id resolution with my custom serialization. How can I do that?
Your idea of using an inner serializer will not work as-is. The id-to-object mapping table is held in a private field JsonSerializerInternalBase._mappings with no way to copy it from the outer serializer to the inner serializer.
As an alternative, you could make a recursive call to serialize using the same serializer, and have the converter disable itself using a thread-static pushdown stack along the lines of Generic method of modifying JSON before being returned to client and JSON.Net throws StackOverflowException when using [JsonConvert()]. You would need to enhance the converters in these examples to manually check for and add the necessary "$id" and "$ref" properties by making use of the JsonSerializer.ReferenceResolver property.
However, since your converters just add properties, a more straightforward solution to your problem might be to create a custom contract resolver that allows types to customize their contract as it is generated via a callback method declared in an attribute applied to the type, for instance:
public class ModifierContractResolver : DefaultContractResolver
{
// As of 7.0.1, Json.NET suggests using a static instance for "stateless" contract resolvers, for performance reasons.
// http://www.newtonsoft.com/json/help/html/ContractResolver.htm
// http://www.newtonsoft.com/json/help/html/M_Newtonsoft_Json_Serialization_DefaultContractResolver__ctor_1.htm
// "Use the parameterless constructor and cache instances of the contract resolver within your application for optimal performance."
// See also https://stackoverflow.com/questions/33557737/does-json-net-cache-types-serialization-information
static ModifierContractResolver instance;
// Explicit static constructor to tell C# compiler not to mark type as beforefieldinit
static ModifierContractResolver() { instance = new ModifierContractResolver(); }
public static ModifierContractResolver Instance { get { return instance; } }
protected override JsonObjectContract CreateObjectContract(Type objectType)
{
var contract = base.CreateObjectContract(objectType);
// Apply in reverse order so inherited types are applied after base types.
foreach (var attr in objectType.GetCustomAttributes<JsonObjectContractModifierAttribute>(true).Reverse())
{
var modifier = (JsonObjectContractModifier)Activator.CreateInstance(attr.ContractModifierType, true);
modifier.ModifyContract(objectType, contract);
}
return contract;
}
}
public abstract class JsonObjectContractModifier
{
public abstract void ModifyContract(Type objectType, JsonObjectContract contract);
}
[System.AttributeUsage(AttributeTargets.Class, AllowMultiple = true, Inherited = true)]
public class JsonObjectContractModifierAttribute : System.Attribute
{
private readonly Type _contractModifierType;
public Type ContractModifierType { get { return _contractModifierType; } }
public JsonObjectContractModifierAttribute(Type contractModifierType)
{
if (contractModifierType == null)
{
throw new ArgumentNullException("contractModifierType");
}
if (!typeof(JsonObjectContractModifier).IsAssignableFrom(contractModifierType))
{
throw new ArgumentNullException(string.Format("{0} is not a subtype of {1}", contractModifierType, typeof(JsonObjectContractModifier)));
}
this._contractModifierType = contractModifierType;
}
}
Then, apply it to your types as in the following example:
[JsonObjectContractModifier(typeof(TestContractModifier))]
public class Test
{
public string A { get; set; }
public string B { get; set; }
public string C { get; set; }
}
class TestContractModifier : JsonObjectContractModifier
{
class EmptyValueProvider : IValueProvider
{
// Explicit static constructor to tell C# compiler not to mark type as beforefieldinit
static EmptyValueProvider() { }
internal static readonly EmptyValueProvider Instance = new EmptyValueProvider();
#region IValueProvider Members
public object GetValue(object target)
{
var test = target as Test;
if (test == null)
return null;
return test.A == null && test.B == null && test.C == null;
}
public void SetValue(object target, object value)
{
var property = target as Test;
if (property == null)
return;
if (value != null && value.GetType() == typeof(bool) && (bool)value == true)
{
property.A = property.B = property.C = null;
}
}
#endregion
}
public override void ModifyContract(Type objectType, JsonObjectContract contract)
{
var jsonProperty = new JsonProperty
{
PropertyName = "isEmpty",
UnderlyingName = "isEmpty",
PropertyType = typeof(bool?),
NullValueHandling = NullValueHandling.Ignore,
Readable = true,
Writable = true,
DeclaringType = typeof(Test),
ValueProvider = EmptyValueProvider.Instance,
};
contract.Properties.Add(jsonProperty);
}
}
And serialize as follows:
var settings = new JsonSerializerSettings
{
PreserveReferencesHandling = PreserveReferencesHandling.Objects, // Or PreserveReferencesHandling.All
ContractResolver = ModifierContractResolver.Instance,
};
var json = JsonConvert.SerializeObject(root, Formatting.Indented, settings);
This produces the following JSON:
[
{
"$id": "1",
"A": "hello",
"B": "goodbye",
"C": "sea",
"isEmpty": false
},
{
"$ref": "1"
},
{
"$id": "2",
"A": null,
"B": null,
"C": null,
"isEmpty": true
},
}
As you can see, both the synthetic "isEmpty" property and reference handling properties are present. Prototype fiddle.

JSON serialization - set default value for int type

I use the exist API and can't change it.
So I have some variable - CellProviderID.
It looks like it is an int, because when I set the int value the server returns the expected response.
"CellProviderID":5,"CellProviderID2":7,"CellProviderID3":2
The problem appears when I leave this value empty and after serialization I get:
"CellProviderID":0,"CellProviderID2":0,"CellProviderID3":0
because 0 is default value for int type. And the server returns an error:
{"ErrorCode":10,"ErrorMessage":"Cell provider was specified, but cell number is blank, Pager provider was specified, but pager number is blank"}
So it looks rather like it's some enum, and 0 hasn't a value.
It works well when I change serialized json from
"CellProviderID":0,"CellProviderID2":0,"CellProviderID3":0
to
"CellProviderID":"","CellProviderID2":"","CellProviderID3":""
How should I initialize the properties to be able to setup int values and get "" when I leave this property empty?
[JsonProperty]
public int CellProviderID { get; set; }
[JsonProperty]
public int CellProviderID2 { get; set; }
[JsonProperty]
public int CellProviderID3 { get; set; }
you can change return type of your properties from int to int?, so you will get null value as default.
It will be serialized as
"CellProviderID":null,"CellProviderID2":null,"CellProviderID3":null
so you can have a deal with that.
Next, you must change your serialization to ignore null values. If you're using Json.Net, you serialization must look like:
JsonConvert.SerializeObject(movie,Formatting.Indented, new JsonSerializerSettings { NullValueHandling = NullValueHandling.Ignore })
So, your server will not receive non-initialized values
You could optionally write a Custom JsonConverter and handle the custom serialization/deserialization yourself.
internal class Inherited
{
public int MyProperty { get; set; }
public int MyProperty2 { get; set; }
}
internal class CustomConverter : JsonConverter
{
public override bool CanConvert(Type objectType)
{
return objectType == typeof(Inherited);
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
throw new NotImplementedException();
}
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
var data = value as Inherited;
if (data != null)
{
writer.WriteStartObject();
foreach (var item in typeof(Inherited).GetProperties())
{
writer.WritePropertyName(item.Name);
switch (item.PropertyType.Name)
{
case "Int32":
{
writer.WriteValue(default(int) == (int)item.GetValue(data, null) ? "" : item.GetValue(data, null).ToString());
break;
}
}
}
writer.WriteEnd();
}
}
}
JsonSerializerSettings obj = new JsonSerializerSettings();
obj.Converters.Add(new CustomConverter());
var result = JsonConvert.SerializeObject(new Inherited(0) { MyProperty = 0, MyProperty2 = 0 }, obj);
Results in -
{"MyProperty":"","MyProperty2":""}

Categories

Resources