i want to change the json property name dynamically and serialize the object.
here is my json for two different entities
For customer
{
"userName": "66666",
"password": "test1234",
"customersList": [
{
"address": "Test Stree2",
"customerNumber": "US01-000281",
"city": ""
}
]
}
For contact
{
"userName": "66666",
"password": "test1234",
"contactList": [
{
"address": "Test stree1",
"contactNumber": "US01-000281",
"city": ""
}
]
}
and the model that is holding this data is as follows
public class URequest<T>
{
[JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
public string userName { get; set; }
[JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
public string password { get; set; }
[JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
public IList<T> requestList { get; set; }
}
in above code requestList could contain list of contacts or customer but while sending i want to change the requestList json property name to respective entity name i.e. for customer it will be customerList and for contact it will be contactList after serializing.
You can create a custom JsonConverter.
Using custom JsonConverter in order to alter the serialization of the portion of an object
Example
public class Customer
{
public string Name { get; set; }
}
public class Client
{
public string Name { get; set; }
}
public class URequest<T>
{
[JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
public string userName { get; set; }
[JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
public string password { get; set; }
[JsonIgnore]
public IList<T> requestList { get; set; }
}
public class URequestConverter<T> : JsonConverter
{
public override bool CanConvert(Type objectType)
{
return (objectType == typeof(URequest<T>));
}
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
var objectType = value.GetType().GetGenericArguments()[0];
URequest<T> typedValue = (URequest<T>) value;
JObject containerObj = JObject.FromObject(value);
containerObj.Add($"{objectType.Name.ToLower()}List", JToken.FromObject(typedValue.requestList));
containerObj.WriteTo(writer);
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
throw new NotImplementedException();
}
}
You can use it like this
[TestMethod]
public void TestMethod1()
{
URequest<Customer> request = new URequest<Customer>();
request.password = "test";
request.userName = "user";
request.requestList = new List<Customer>();
request.requestList.Add(new Customer() { Name = "customer" });
JsonSerializerSettings settings = new JsonSerializerSettings();
settings.Formatting = Formatting.Indented;
settings.Converters.Add(new URequestConverter<Customer>());
Console.WriteLine(JsonConvert.SerializeObject(request, settings));
}
using the ContentResolver i have solve the issue
here is the code
public class UserRequestResolver : DefaultContractResolver
{
private string propertyName;
public UserRequestResolver()
{
}
public UserRequestResolver(string name)
{
propertyName = name;
}
public new static readonly UserRequestResolver Instance = new UserRequestResolver();
protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization)
{
JsonProperty property = base.CreateProperty(member, memberSerialization);
if (property.PropertyName == "requestList")
{
property.PropertyName = propertyName;
}
return property;
}
}
once can pass specific property name in the constructor.
JsonSerializerSettings settings = new JsonSerializerSettings();
settings.ContractResolver = new UserRequestResolver("contactList");
Related
Let's say I have the following class structure (Building is an abstract class):
public class Street
{
public string StreetName { get; set; }
public Building[] Buildings { get; set; }
}
public abstract class Building
{
public string Name { get; set; }
}
public class House : Building
{
public int Floors { get; set; }
}
public class Flat : Building
{
public int WhichFloor { get; set; }
}
I then create a street object with a few flats in the buildings array:
Flat f1 = new Flat { Name = "Flat 1", WhichFloor = 1 };
Flat f2 = new Flat { Name = "Flat 2", WhichFloor = 2 };
Street street = new Street
{
StreetName = "Street Name",
Buildings = new[] { f1, f2 }
};
Using JsonConvert I then Serialize the object:
var toJson = JsonConvert.SerializeObject(street);
Now I want to convert the json back to a street object:
var fromJson = JsonConvert.DeserializeObject<Street>(toJson);
This fails with the following error:
"Could not create an instance of type Building. Type is an interface or abstract class and cannot be instantiated. Path 'Buildings[0].WhichFloor'"
How can I tell the JsonConvert class that Buildings should be an array of flats?
As per #Evk's shared link, you should try setting TypeNameHandling to TypeNameHandling.Auto while serializing and deserializing:
var toJson = JsonConvert.SerializeObject(street, Newtonsoft.Json.Formatting.Indented, new JsonSerializerSettings
{
TypeNameHandling = TypeNameHandling.Auto
});
var fromJson = JsonConvert.DeserializeObject<Street>(toJson, new JsonSerializerSettings
{
TypeNameHandling = TypeNameHandling.Auto
});
public abstract class JsonCreationConverter<T> : JsonConverter
{
protected abstract T Create(Type objectType, JObject jObject);
public override bool CanConvert(Type objectType)
{
return typeof(T) == objectType;
}
public override object ReadJson(JsonReader reader,Type objectType,
object existingValue, JsonSerializer serializer)
{
try
{
var jObject = JObject.Load(reader);
var target = Create(objectType, jObject);
serializer.Populate(jObject.CreateReader(), target);
return target;
}
catch (JsonReaderException)
{
return null;
}
}
public override void WriteJson(JsonWriter writer, object value,
JsonSerializer serializer)
{
throw new NotImplementedException();
}
}
Now implement this interface
public class SportActivityConverter : JsonCreationConverter<BaseSportActivity>
{
protected override BaseSportActivity Create(Type objectType, JObject jObject)
{
BaseSportActivity result = null;
try
{
switch ((ESportActivityType)jObject["activityType"].Value<int>())
{
case ESportActivityType.Football:
result = jObject.ToObject<FootballActivity>();
break;
case ESportActivityType.Basketball:
result = jObject.ToObject<BasketballActivity>();
break;
}
}
catch(Exception ex)
{
Debug.WriteLine(ex);
}
return result;
}
}
I have a class. It has several properties lets say 10. Out of these 10, 3 are filled with data remaining 7 are blank.i.e. empty strings "" Used this link as reference. I would like only NON-NULL and NON-EMPTY string properties to be shown. But the end output has all 10 properties. I want only to see 3.
namespace Mynamespace.ValueObjects
{
[DataContract]
public class User
{
[DataMember(Name ="userID", IsRequired = false,EmitDefaultValue = false)]
public string userID { get; set; }
[DataMember(Name ="ssn", IsRequired = false,EmitDefaultValue = false)]
public string ssn { get; set; }
[DataMember(Name ="empID", IsRequired = false,EmitDefaultValue = false)]
public string empID { get; set; }
[DataMember(Name ="schemaAgencyName", IsRequired = false,EmitDefaultValue = false)]
public string schemaAgencyName { get; set; }
[DataMember(Name ="givenName", IsRequired = false,EmitDefaultValue = false)]
public string givenName { get; set; }
[DataMember(Name ="familyName", IsRequired = false,EmitDefaultValue = false)]
public string familyName { get; set; }
[DataMember(Name ="password", IsRequired = false,EmitDefaultValue = false)]
public string password { get; set; }
....
}
}
I also tried with
[JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
as the attribute too. No luck. I also did like this
var t = JsonConvert.SerializeObject(usr, Newtonsoft.Json.Formatting.None,
new JsonSerializerSettings
{NullValueHandling = NullValueHandling.Ignore});
where 'usr' is the User instance. By no luck I mean, the 't' comes back with all the 10 properties
{"userID":"vick187","ssn":"","empID":"","schemaAgencyName":"","givenName":"","familyName":"","password":"pwd1234",...}
So as you can see only userID and password are populated. But I have ssn, empID etc still showing up. I only want userID and password. Any help would be appreciated.
Just decorating the properties [JsonProperty(NullValueHandling = NullValueHandling.Ignore)] ONLY should do what you want. Unless the property is getting set to an empty string.
Just wondering, why do you need the DataMemeber attribute?
Here is a link to a working dotnetfiddle
using System;
using Newtonsoft.Json;
using System.ComponentModel;
public class Program
{
public static void Main()
{
var user = new User();
user.UserID = "1234";
user.ssn = "";
var settings = new JsonSerializerSettings();
settings.NullValueHandling = NullValueHandling.Ignore;
settings.DefaultValueHandling = DefaultValueHandling.Ignore;
Console.WriteLine(JsonConvert.SerializeObject(user, settings));
}
}
public class User
{
[DefaultValue("")]
public string UserID { get; set; }
[DefaultValue("")]
public string ssn { get; set; }
[DefaultValue("")]
public string empID { get; set; }
[DefaultValue("")]
public string schemaAgencyName { get; set; }
[DefaultValue("")]
public string givenName { get; set; }
[DefaultValue("")]
public string familyName { get; set; }
[DefaultValue("")]
public string password { get; set; }
}
You can also use two annotations as follows:
[DefaultValue("")]
[JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)]
public string Category { get; set; }
Although the accepted answers works, it also removes integer properties of zero value. I was looking for something more generic to work with large objects.
Found a great answer here: https://codearticles.ru/articles/2905?AspxAutoDetectCookieSupport=1
And consolidated it for our use case as below:
public class ShouldSerializeContractResolver : DefaultContractResolver
{
public static readonly ShouldSerializeContractResolver Instance = new ShouldSerializeContractResolver();
protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization)
{
JsonProperty property = base.CreateProperty(member, memberSerialization);
if (property.PropertyType == typeof(string))
{
// Do not include emptry strings
property.ShouldSerialize = instance =>
{
return !string.IsNullOrWhiteSpace(instance.GetType().GetProperty(member.Name).GetValue(instance, null) as string);
};
}
else if (property.PropertyType == typeof(DateTime))
{
// Do not include zero DateTime
property.ShouldSerialize = instance =>
{
return Convert.ToDateTime(instance.GetType().GetProperty(member.Name).GetValue(instance, null)) != default(DateTime);
};
}
else if (typeof(IEnumerable).IsAssignableFrom(property.PropertyType))
{
// Do not include zero-length lists
switch (member.MemberType)
{
case MemberTypes.Property:
property.ShouldSerialize = instance =>
{
var enumerable = instance.GetType().GetProperty(member.Name).GetValue(instance, null) as IEnumerable;
return enumerable != null ? enumerable.GetEnumerator().MoveNext() : false;
};
break;
case MemberTypes.Field:
property.ShouldSerialize = instance =>
{
var enumerable = instance.GetType().GetField(member.Name).GetValue(instance) as IEnumerable;
return enumerable != null ? enumerable.GetEnumerator().MoveNext() : false;
};
break;
}
}
return property;
}
}
This can be used as follows:
JsonConvert.SerializeObject(o,
Newtonsoft.Json.Formatting.None,
new JsonSerializerSettings
{
NullValueHandling = NullValueHandling.Ignore,
ContractResolver = ShouldSerializeContractResolver.Instance
});
i have done this with a converter.
using System;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
namespace TestApp.JsonConverterResolver
{
public class IgnoreEmptyStringsConverter : JsonConverter
{
#region Methods
public override bool CanConvert(Type objectType)
{
return objectType == typeof(string);
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue,
JsonSerializer serializer)
{
var theValue = reader.Value?.ToString();
return !string.IsNullOrWhiteSpace(theValue) ? theValue : null;
}
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
if (!string.IsNullOrWhiteSpace(value.ToString()))
{
JToken token = JToken.FromObject(value.ToString(), serializer);
token.WriteTo(writer);
return;
}
writer.WriteNull();
}
#endregion
}
}
Example person model class:
public class Person
{
public string Name { get; set; }
}
And the ueage:
var serializerSettings = new JsonSerializerSettings
{
Formatting = Newtonsoft.Json.Formatting.Indented,
NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore,
Converters = new List<JsonConverter> {new IgnoreEmptyStringsConverter()}
};
var person = JsonConvert.DeserializeObject<Person>("{ \"Name\":\"\" }", serializerSettings);
var jsonPerson = JsonConvert.SerializeObject(new Person { Name = "" }, serializerSettings);
I just wrote that out of my head.
But I think that's how I solved it at some point.
Maybe it helps someone.
I am looking for a way to partially serialize a model to Json using Json.Net. How the partial serialization should look like I want to define on the property of a parent object. So partial serialization can look different for different parent models. To illustrate what I want here some code:
private class MyTestObject
{
[SerializeOnly("TestValue1")]
[SerializeOnly("TestValue3")]
public ComplexTestObject Property1 { get; set; }
public MyTestObject()
{
Property1 = new ComplexTestObject();
}
}
private class ComplexTestObject
{
public string TestValue1 { get; set; }
public string TestValue2 { get; set; }
public string TestValue3 { get; set; }
public ComplexTestObject()
{
TestValue1 = "value1";
TestValue2 = "value2";
TestValue3 = "value3";
}
}
Now when I serialize an instance of class MyTestObject I want to get the following Json:
{
"Property1" : {
"TestValue1" : "value1",
"TestValue3" : "value3",
}
}
You can see that SerializeOnly is used to define which properties are to be serialized.
To achieve this I can create a SerializeOnlyAttribute. When trying to use this in a custom Serialization ContractResolver I can only see the attributes of the specific member and so I cannot see any SerializeOnlyAttribute because they reside on the parent.
Is there a simple way to achieve the desired behavior with Json.Net? It might be possible writing a custom JsonConverter but how can this be built such that only handling the attributes is covered and still the default converters are used?
You can solve this in two parts:
Create a custom JsonConverter that can accept a list of names of properties to serialize.
Create a custom ContractResolver that looks for properties that have at least one [SerializeOnly] attribute applied, and apply the custom converter to those properties, passing the list of child property names gathered from the applied attributes.
Here is what the resolver might look like:
class CustomResolver : DefaultContractResolver
{
protected override IList<JsonProperty> CreateProperties(Type type, MemberSerialization memberSerialization)
{
IList<JsonProperty> props = base.CreateProperties(type, memberSerialization);
foreach (JsonProperty prop in props)
{
if (!prop.PropertyType.IsPrimitive && prop.PropertyType != typeof(string))
{
PropertyInfo pi = type.GetProperty(prop.UnderlyingName);
if (pi != null && pi.CanRead)
{
var childPropertiesToSerialize = pi.GetCustomAttributes<SerializeOnly>()
.Select(att => att.PropertyName);
if (childPropertiesToSerialize.Any())
{
prop.Converter = new CustomConverter(childPropertiesToSerialize);
}
}
}
}
return props;
}
}
And here is the converter:
class CustomConverter : JsonConverter
{
private HashSet<string> propertiesToSerialize;
public CustomConverter(IEnumerable<string> propertiesToSerialize)
{
this.propertiesToSerialize = new HashSet<string>(propertiesToSerialize);
}
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
writer.WriteStartObject();
foreach (PropertyInfo prop in value.GetType().GetProperties())
{
if (prop.CanRead && propertiesToSerialize.Contains(prop.Name))
{
writer.WritePropertyName(prop.Name);
serializer.Serialize(writer, prop.GetValue(value));
}
}
writer.WriteEndObject();
}
public override bool CanRead
{
get { return false; }
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
throw new NotImplementedException();
}
public override bool CanConvert(Type objectType)
{
throw new NotImplementedException();
}
}
Demo:
class Program
{
static void Main(string[] args)
{
var test = new MyTestObject();
var settings = new JsonSerializerSettings();
settings.ContractResolver = new CustomResolver();
settings.Formatting = Formatting.Indented;
var json = JsonConvert.SerializeObject(test, settings);
Console.WriteLine(json);
}
class MyTestObject
{
[SerializeOnly("TestValue1")]
[SerializeOnly("TestValue3")]
public ComplexTestObject Property1 { get; set; }
[SerializeOnly("TestValue2")]
public ComplexTestObject Property2 { get; set; }
public MyTestObject()
{
Property1 = new ComplexTestObject();
Property2 = new ComplexTestObject();
}
}
class ComplexTestObject
{
public string TestValue1 { get; set; }
public string TestValue2 { get; set; }
public string TestValue3 { get; set; }
public ComplexTestObject()
{
TestValue1 = "value1";
TestValue2 = "value2";
TestValue3 = "value3";
}
}
}
Output:
{
"Property1": {
"TestValue1": "value1",
"TestValue3": "value3"
},
"Property2": {
"TestValue2": "value2"
}
}
Fiddle: https://dotnetfiddle.net/Fj7QcW
C# already has an attribute to help you with this
https://msdn.microsoft.com/en-us/library/system.web.script.serialization.scriptignoreattribute(v=vs.110).aspx
[ScriptIgnore]
public string MyParam{get;set;}
I want to modify JSON.NET so that when I am serializing a Model from my API it sends only an array of IDs for a composite Collection object.
For example:
class Employee
{
public ICollection<Address> Addresses { get; set; }
}
class Address
{
public int id;
public string location;
public string postcode;
}
Then when I send that back through WebApi
Request.Createresponse(HttpStatusCode.OK, new Employee());
Instead of this:
{
"Addresses" :
[
{"id" : 1, "location" : "XX", "postcode" : "XX" },
{"id" : 2, "location" : "XX", "postcode" : "XX" }
]
}
It just sends as this:
{
"Addresss" : [1,2]
}
I want this to be happening application-wide and I don't want to modify at the specific place.
How can I achieve this using the JSON.NET serializer?
You can get the result you want using a custom JsonConverter such as this:
class IdOnlyListConverter : JsonConverter
{
public override bool CanConvert(Type objectType)
{
return (typeof(IEnumerable).IsAssignableFrom(objectType) &&
objectType != typeof(string));
}
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
JArray array = new JArray();
foreach (object item in (IEnumerable)value)
{
PropertyInfo idProp = item.GetType().GetProperty("id");
if (idProp != null && idProp.CanRead)
{
array.Add(JToken.FromObject(idProp.GetValue(item, null)));
}
}
array.WriteTo(writer);
}
public override bool CanRead
{
get { return false; }
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
throw new NotImplementedException();
}
}
In your model, wherever you have a collection of something where you only want the IDs, decorate the collection property with a [JsonConverter] attribute specifying the custom converter. For example:
class Employee
{
public string name { get; set; }
[JsonConverter(typeof(IdOnlyListConverter))]
public ICollection<Address> Addresses { get; set; }
}
class Address
{
public int id { get; set; }
public string location { get; set; }
public string postcode { get; set; }
}
When the collection gets serialized, the converter will be used, and only the ID values will be written out. Demo:
class Program
{
static void Main(string[] args)
{
Employee emp = new Employee
{
name = "Joe",
Addresses = new List<Address>
{
new Address { id = 1, location = "foo", postcode = "bar" },
new Address { id = 2, location = "baz", postcode = "quux" }
}
};
string json = JsonConvert.SerializeObject(emp);
Console.WriteLine(json);
}
}
Output:
{"name":"Joe","Addresses":[1,2]}
Please have a look at Json.Net's documentation.
public class Address
{
[JsonProperty("Id")]
public int I'd { get; set; }
[JsonIgnore]
public string Location { get; set; }
[JsonIgnore]
public string PostalCode { get; set; }
}
The only drawback to this is that you'll never be able to serialize the Location and PostalCode properties to JSON should you ever want to.
I believe there is a way to specify the serialization that should be used when serializing to JSON with Json.Net. Again, have a look at their documentation.
I have a very undesirable situation which requires me to deserialize the JSON where the values are field names with JSON.NET. Assuming that I have the following JSON which is very properly structured:
{
"name": "tugberk",
"roles": [
{ "id": "1", "name": "admin" },
{ "id": "2", "name": "guest" }
]
}
It's very easy to deserialize this with JSON.NET to a CLR object:
class Program
{
static void Main(string[] args)
{
var camelCaseSettings = new JsonSerializerSettings { ContractResolver = new CamelCasePropertyNamesContractResolver() };
var text = File.ReadAllText("user_normal.txt");
var obj = JsonConvert.DeserializeObject<User>(text, camelCaseSettings);
}
}
public class User
{
public string Name { get; set; }
public Role[] Roles { get; set; }
}
public class Role
{
public int Id { get; set; }
public string Name { get; set; }
}
However, in my current case, I have the following horrible JSON which is equivalent to above JSON in terms of values:
{
"name": "tugberk",
"roles": {
"1": { "name": "admin" },
"2": { "name": "guest" }
}
}
As you can see, roles field is not an array; it's an object which contains other values as objects with it's unique keys as their field names (which is horrible). What's the best way to deserialize this JSON to above User class with JSON.NET?
You can create a custom JsonConverter which serializes/deserializes Role[]. You can then decorate your Roles property with the JsonConverterAttribute like this:
public class User
{
public string Name { get; set; }
[JsonConverter(typeof(RolesConverter))]
public Role[] Roles { get; set; }
}
In your converter class you are able to read an object and return an array instead. Your converter class may look like this:
class RolesConverter : JsonConverter
{
public override bool CanConvert(Type objectType)
{
return objectType == typeof(Role[]);
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
// deserialize as object
var roles = serializer.Deserialize<JObject>(reader);
var result = new List<Role>();
// create an array out of the properties
foreach (JProperty property in roles.Properties())
{
var role = property.Value.ToObject<Role>();
role.Id = int.Parse(property.Name);
result.Add(role);
}
return result.ToArray();
}
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
throw new NotImplementedException();
}
}
There are a few options available to you. You could have a custom JsonConverter and serialize it manually. Since by the time of writing this fero provided an answer based on this, I'll give you an alternative, requiring two surrogate classes:
public class JsonUser
{
public string Name { get; set; }
public Dictionary<int, JsonRole> Roles { get; set; }
}
public class JsonRole
{
public string Name { get; set; }
}
And in your Role class:
public static implicit operator User(JsonUser user)
{
return new User
{
Name = user.Name,
Roles = user.Roles
.Select(kvp => new Role { Id = kvp.Key, Name = kvp.Value.Name})
.ToArray()
};
}
Which can be used like this:
User jsonUser = JsonConvert.DeserializeObject<JsonUser>(json);
Now, this is done at the expense of creating an intermediate object and probably isn't suited for most cases.
For the sake of completeness, I'll include my version of the JsonConverter solution:
public class UserRolesConverter : JsonConverter
{
public override bool CanConvert(Type objectType)
{
return objectType == typeof (Role[]);
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
return serializer.Deserialize<JObject>(reader)
.Properties()
.Select(p => new Role
{
Id = Int32.Parse(p.Name),
Name = (string) p.Value["name"]
})
.ToArray();
}
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
throw new NotImplementedException();
}
}
public class User
{
public string Name { get; set; }
[JsonConverter(typeof(UserRolesConverter))]
public Role[] Roles { get; set; }
}
var jsonUser = JsonConvert.DeserializeObject<User>(json);
Hm you can try:
dynamic jObject = JObject.Parse(text);
List<User> users = new List<User>();
foreach(dynamic dUser in jObject)
{
List<Role> roles = new List<Role>();
User user = new User();
user.Name = dUser.name;
foreach(PropertyInfo info in dUser.GetType().GetProperties())
{
Role role = new Role();
role.Id = info.Name;
role.Name = dUser[info.Name].name;
roles.Ad(role);
}
user.Roles = roles.ToArray();
}