I have some data in a C# DataSet object. I can serialize it right now using a Json.net converter like this
DataSet data = new DataSet();
// do some work here to populate 'data'
string output = JsonConvert.SerializeObject(data);
However, this uses the property names from data when printing to the .json file. I would like to change the property names to be something different (say, change 'foo' to 'bar').
In the Json.net documentation, under 'Serializing and Deserializing JSON' → 'Serialization Attributes' it says "JsonPropertyAttribute... allows the name to be customized". But there is no example. Does anyone know how to use a JsonPropertyAttribute to change the property name to something else?
(Direct link to documentation)
Json.net's documentation seems to be sparse. If you have a great example I'll try to get it added to the official documentation.
Thanks!
You could decorate the property you wish controlling its name with the [JsonProperty] attribute which allows you to specify a different name:
using Newtonsoft.Json;
// ...
[JsonProperty(PropertyName = "FooBar")]
public string Foo { get; set; }
Documentation: Serialization Attributes
If you don't have access to the classes to change the properties, or don't want to always use the same rename property, renaming can also be done by creating a custom resolver.
For example, if you have a class called MyCustomObject, that has a property called LongPropertyName, you can use a custom resolver like this…
public class CustomDataContractResolver : DefaultContractResolver
{
public static readonly CustomDataContractResolver Instance = new CustomDataContractResolver ();
protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization)
{
var property = base.CreateProperty(member, memberSerialization);
if (property.DeclaringType == typeof(MyCustomObject))
{
if (property.PropertyName.Equals("LongPropertyName", StringComparison.OrdinalIgnoreCase))
{
property.PropertyName = "Short";
}
}
return property;
}
}
Then call for serialization and supply the resolver:
var result = JsonConvert.SerializeObject(myCustomObjectInstance,
new JsonSerializerSettings { ContractResolver = CustomDataContractResolver.Instance });
And the result will be shortened to {"Short":"prop value"} instead of {"LongPropertyName":"prop value"}
More info on custom resolvers here
There is still another way to do it, which is using a particular NamingStrategy, which can be applied to a class or a property by decorating them with [JSonObject] or [JsonProperty].
There are predefined naming strategies like CamelCaseNamingStrategy, but you can implement your own ones.
The implementation of different naming strategies can be found here: https://github.com/JamesNK/Newtonsoft.Json/tree/master/Src/Newtonsoft.Json/Serialization
You can directly use
[JsonProperty(Name = "access_token")]
public string AccessToken { get; set; }
or
[JsonProperty("access_token")]
public string AccessToken { get; set; }
and serialize using Newthonsoft.Json library will be detect how change it
Related
I have some data in a C# DataSet object. I can serialize it right now using a Json.net converter like this
DataSet data = new DataSet();
// do some work here to populate 'data'
string output = JsonConvert.SerializeObject(data);
However, this uses the property names from data when printing to the .json file. I would like to change the property names to be something different (say, change 'foo' to 'bar').
In the Json.net documentation, under 'Serializing and Deserializing JSON' → 'Serialization Attributes' it says "JsonPropertyAttribute... allows the name to be customized". But there is no example. Does anyone know how to use a JsonPropertyAttribute to change the property name to something else?
(Direct link to documentation)
Json.net's documentation seems to be sparse. If you have a great example I'll try to get it added to the official documentation.
Thanks!
You could decorate the property you wish controlling its name with the [JsonProperty] attribute which allows you to specify a different name:
using Newtonsoft.Json;
// ...
[JsonProperty(PropertyName = "FooBar")]
public string Foo { get; set; }
Documentation: Serialization Attributes
If you don't have access to the classes to change the properties, or don't want to always use the same rename property, renaming can also be done by creating a custom resolver.
For example, if you have a class called MyCustomObject, that has a property called LongPropertyName, you can use a custom resolver like this…
public class CustomDataContractResolver : DefaultContractResolver
{
public static readonly CustomDataContractResolver Instance = new CustomDataContractResolver ();
protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization)
{
var property = base.CreateProperty(member, memberSerialization);
if (property.DeclaringType == typeof(MyCustomObject))
{
if (property.PropertyName.Equals("LongPropertyName", StringComparison.OrdinalIgnoreCase))
{
property.PropertyName = "Short";
}
}
return property;
}
}
Then call for serialization and supply the resolver:
var result = JsonConvert.SerializeObject(myCustomObjectInstance,
new JsonSerializerSettings { ContractResolver = CustomDataContractResolver.Instance });
And the result will be shortened to {"Short":"prop value"} instead of {"LongPropertyName":"prop value"}
More info on custom resolvers here
There is still another way to do it, which is using a particular NamingStrategy, which can be applied to a class or a property by decorating them with [JSonObject] or [JsonProperty].
There are predefined naming strategies like CamelCaseNamingStrategy, but you can implement your own ones.
The implementation of different naming strategies can be found here: https://github.com/JamesNK/Newtonsoft.Json/tree/master/Src/Newtonsoft.Json/Serialization
You can directly use
[JsonProperty(Name = "access_token")]
public string AccessToken { get; set; }
or
[JsonProperty("access_token")]
public string AccessToken { get; set; }
and serialize using Newthonsoft.Json library will be detect how change it
I have never used Web API before, but I need a web service that will accept/return JSON objects and using this seemed like a reasonable thing. It looked pretty simple (if not a bit of overkill for my purposes), but a data structure I need to deal with looks something like:
{
"values":["foo", "bar"],
"default":"bar"
}
And so I went to make a Model object:
class DropDownValues {
public string[] values { get; set; }
public string default { get; set; }
}
Problem is that default seems to be a protected keyword. There must be some way to get around that, right?
You can use keywords in C# as identifiers by prepending # in front of them.
I would suggest to go different way. Keep your C# object model as much standard as possible (I wouldn't use # sign and C# keywords as property name).
We can separate the serialized (JSON) world and C# objects - just by using the Json.NET features.
One of the simpliest to use is decoration with Attribute:
[JsonProperty(PropertyName = "default")]
public string DefaultValue { get; set; }
In this case we have to reference Newtonsoft.Json in the project. If it must be POCO, we can introduce CustomResolver derrived from DefaultContractResolver and define these conversions there...
But separation of concern in this case is a bit more pure solution, I would say
EDIT: JSON Contract Resolver draft (see comments)
Important NOTE: Newtonsoft.Json is part of the Web API. Not only it is an open source, but even MS team bet on that as a core JSON serializer.
1) Newtonsoft.Json (as a part of the Web.API) is already installed in your solution. So you do not have to downloaded (nuget) separately. It would always be in your packages folder. So, to use the attribute is just adding the reference. It is there...
2) There is a small draft how to do the attribute stuff, while keeping the POCO. As I've tried explain here: POCO's, behavior and Peristance Igorance, to keep POCO (e.g. we do profit from layered Architecture with NHibernate on a data layer), we can replace attributes with a Contract Resolver. Our POCO library does not have to reference anything
We just have to do extend the service layer:
public class MyResolver : DefaultContractResolver
{
protected override JsonProperty CreateProperty(
MemberInfo member,
MemberSerialization memberSerialization)
{
var jProperty = base.CreateProperty(member, memberSerialization);
var propertyInfo = member as PropertyInfo;
if (propertyInfo == null)
{
return jProperty;
}
// just adjust in case if Property name is DefaultValue
var isDefaultValueProeprty =
propertyInfo.Name.Equals("DefaultValue");
if(isDefaultValueProeprty)
{
jProperty.PropertyName = "default";
}
return jProperty;
}
...
This way we've provided the same information to serailizer as with the [JsonPropertyAttribute].
Now, we just have to use it. There are many ways (e.g. global) but we can do it for a controller only:
protected override void Initialize(HttpControllerContext context)
{
base.Initialize(context);
var jSettings = context.Configuration.Formatters.JsonFormatter.SerializerSettings;
jSettings.ContractResolver = MyResolver;
}
The class DropDownValues using camel convention:
class DropDownValues {
public string[] values { get; set; }
public string default { get; set; }
}
You can use prefix # to passby but it is still not following C# coding convention.
The better solution which you can both avoid reserved keyword and still use C# coding convention is using CamelCasePropertyNamesContractResolver:
class DropDownValues {
public string[] Values { get; set; }
public string Default { get; set; }
}
And customize JsonFormatter to avoid convention mismatch between C# and json object as below:
var jsonFormatter = configuration.Formatters.JsonFormatter;
jsonFormatter.SerializerSettings = new JsonSerializerSettings()
{
ContractResolver = new CamelCasePropertyNamesContractResolver()
};
This is a follow-up question to this one. What I am trying to achieve is to substitue [JsonConstructor] from my classes in order to get rid of the dependency to Json.Net in projects where I am not doing any serialization. With what I have gathered from other sources, using a ContractResolver is the way to go to implement some kind of "for type Foo use delegate Bar to create an instance of it"-mapping (see MongoDB's class map). What's important to me is, that I want to stick with my readonly fields in my entities and therefore I must use some factory methods with parameters to create instances while the given arguments get assigned to the readonly fields during the creation process.
I have come up with the following solution (I went from having a public parameterless constructor, to a attributed constructor, to a private parameterless constructor, to no attributed constructor at all and with every step I explored the behavior in the overriden methods of my contract resolver):
class Thing
{
public int Id { get; private set; }
public string Name { get; private set; }
//private Thing() { }
//[JsonConstructor]
private Thing(int id, string name)
{
this.Id = id;
this.Name = name;
}
public static Thing Create(int id, string name)
{
return new Thing(id, name);
}
public static object Create2(object[] values)
{
return new Thing((int)values[0], (string)values[1]);
}
}
My contract resolver looks as follows:
class CustomResolver : DefaultContractResolver
{
public override JsonContract ResolveContract(Type type)
{
var b = base.ResolveContract(type);
if(type == typeof(Thing))
{
var bb = b as JsonObjectContract;
// figured out the name of the backing field using ILSpy
var prop = typeof(JsonObjectContract).GetField("_creatorParameters",
System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance);
// in order to set the value of property CreatorParameters
// which is used as parameter when OverrideCreator is invoked
prop.SetValue(bb, bb.Properties);
bb.OverrideCreator = new ObjectConstructor<object>(Thing.Create2);
}
return b;
}
}
And this is the usage of it:
Thing t1 = Thing.Create("Flim", 1);
// Serializer settings
JsonSerializerSettings settings = new JsonSerializerSettings();
settings.ContractResolver = new CustomResolver();
settings.PreserveReferencesHandling = PreserveReferencesHandling.None;
settings.ReferenceLoopHandling = ReferenceLoopHandling.Ignore;
settings.Formatting = Newtonsoft.Json.Formatting.Indented;
string json = JsonConvert.SerializeObject(t1, settings);
Thing t2 = JsonConvert.DeserializeObject<Thing>(json, settings);
It works as I expect it, but since I have hacked the system by using reflection I am convinced that I am doing something completely wrong and that there must be a cleaner way. Any ideas?
EDIT
What I have not thought of until now is, that I have some classes which are attributed with [JsonConverter(typeof(SomeSubstituteType))] which I would also get rid of if I want to elmininate the depency completely. These classes are so far not included in the type check in the contract resolver class. Is there an elegant way to make it work without the attribute and without adding the additional checks in the resolver by somehow configuring the JsonSerializerSettings additionally to what is configured so far?
It's true that DefaultContractResolver doesn't currently make it easy to inject logic to choose a custom constructor, since:
JsonObjectContract.OverrideConstructor is marked as obsolete.
DefaultContractResolver.GetAttributeConstructor is private and non-virtual.
Nevertheless you can make the following improvements to your code:
Override CreateObjectContract rather than ResolveContract. The former is called the first time a object of a given type type is encountered to construct a contract for the type which is subsequently cached. The latter is called for every object encountered including primitives. Thus overriding the former will be more performant. Also, CreateObjectContract() is within a thread-safe lock while ResolveContract() is not and can be called from multiple threads simultaneously. Thus your current code might not be thread safe.
JsonObjectContract.CreatorParameters is a mutable collection so you can just clear the contents and add new properties.
Thus your contract resolver could look like:
class CustomResolver : DefaultContractResolver
{
protected override JsonObjectContract CreateObjectContract(Type objectType)
{
var contract = base.CreateObjectContract(objectType);
if (objectType == typeof(Thing))
{
contract.CreatorParameters.Clear();
// For safety, specify the order concretely.
contract.CreatorParameters.AddProperty(contract.Properties["Id"]); // Use nameof() in latest version.
contract.CreatorParameters.AddProperty(contract.Properties["Name"]); // Use nameof() in latest version.
contract.OverrideCreator = new ObjectConstructor<object>(Thing.Create2);
}
return contract;
}
}
Example fiddle.
Update
I have some classes which are attributed with [JsonConverter(typeof(SomeSubstituteType))] which I would also get rid of if I want to elmininate the depency completely... Is there an elegant way to make it work without the attribute and without adding the additional checks in the resolver by somehow configuring the JsonSerializerSettings additionally to what is configured so far?
Yes, make sure that JsonConverter.CanConvert() is implemented for your converters, then add them to JsonSerializerSettings.Converters:
public class SomeSubstituteType : JsonConverter
{
public override bool CanConvert(Type objectType)
{
return typeof(SomeOriginalType).IsAssignableFrom(objectType);
}
// Remainder as before
}
And then do:
var settings = new JsonSerializerSettings
{
Converters = { new SomeSubstituteType(), new SecondConverter(), ... },
};
I was working on an enhancement in my Xamarin Android app to make working with Android's saved state easier. One part of the implementation for this needs to Json serialize the properties of current Activity class that have the custom [SaveState] attribute. All other properties are ignored. I've got this mechanism working using a POCO (and Json.NET as serializer). When defining a public property with the custom [SaveState] attribute, it serializes (only) that property as desired.
When I define a class that extends the (obviously) required Activity class, lets call it ExampleActivity, it doesn't serialize the public property anymore. So, the same setup that was working for the POCO isn't working anymore when extending the Activity.
In addition: it's not serializing anything of the ExampleActivity or of the inherited Activity's properties. Even though many are public. Just an empty Json string object.
When I add the [JsonProperty] attribute to the public property it d̲o̲e̲s̲ though! So I believe it's not a matter that Json.NET can't serialize the property, it just won't. For some reason it's ignoring it and everything else.
I've tried some things, but I can't seem to figure out why it's ignoring the properties. I've added a TraceWriter to the serializer in the hopes to see something that might point me in the right direction, but it doesn't.
I've added a small stripped code snippet that reproduces the issue:
public static class Example
{
public static void Run()
{
var exampleActivity = new ExampleActivity { PropertyA = "A value", PropertyB = "B value" };
// Default serializer settings with a memory trace writer
var serializerSettings = new JsonSerializerSettings { TraceWriter = new MemoryTraceWriter() };
var serializedString = JsonConvert.SerializeObject(exampleActivity, serializerSettings);
System.Diagnostics.Debug.WriteLine(serializerSettings.TraceWriter);
// NOTE: The serialized string only contains PropertyB
System.Diagnostics.Debug.WriteLine($"SerializedString: {serializedString}");
}
public class ExampleActivity : Activity
{
//[JsonProperty]
public string PropertyA { get; set; }
[JsonProperty]
public string PropertyB { get; set; }
}
}
When calling the static Example.Run() you'll see that even though the ExampleActivity's PropertyA is a regular public property it's not serialized. Whereas the PropertyB which has the [JsonProperty] attribute i̲s̲ serialized.
For my solution I don't want to be adding the [JsonProperty] attribute to each property that also get's the custom [SaveState] attribute. That it's currently using Json (de)serializing behind the scenes to achieve the desired behavior shouldn't have influence on the usage of the [SaveState] behavior.
I hope I've been sufficiently complete in the describing of my issue. Does anybody know why the regular public properties of the class extending the Activity aren't serialized? And/or how to fix this?
I am retrieving JSON from an API. I am using newtonsoft (this is json.net right?) to deserialize this into a list of objects. It works.
Unfortunately I also need to pass this along to someone else as JSON (they can't call the API directly only I have access to it). I say unfortunately because I need to OUTPUT my JSON that is different from what is being received (the property names need to be different).
For example, I have a class called Person, with a property called Name. I want to get "People", so I make my request to that API to get JSON as above, and get back a list of Person. Unfortunately the API doesn't return me people with Name properties, it returns me pname. So to map this, I just do:
[JsonProperty("pname")]
This is all well and good - it converts pname to name and my class now has the value! I have a list of people with names.
Now I need to give this list of objects BACK to someone else as "Name", However when I serialize my people class back to JSON, it writes out the JSON as "pname" when I really want to write it out as "Name". I suspect it's picking up the "JsonProperty".
Is there a way to just have it use pname for deserialization, but use the original property value for serialization?
Thanks!
You can create a custom contract resolver that sets the property names back to the ones you've defined in the C# class before serilization. Below is some example code;
class OriginalNameContractResolver : DefaultContractResolver
{
protected override IList<JsonProperty> CreateProperties(Type type, MemberSerialization memberSerialization)
{
// Let the base class create all the JsonProperties
IList<JsonProperty> list = base.CreateProperties(type, memberSerialization);
// assign the C# property name
foreach (JsonProperty prop in list)
{
prop.PropertyName = prop.UnderlyingName;
}
return list;
}
}
Use it like this;
JsonSerializerSettings settings = new JsonSerializerSettings();
settings.Formatting = Formatting.Indented;
if (useLongNames)
{
settings.ContractResolver = new OriginalNameContractResolver();
}
string response = JsonConvert.SerializeObject(obj, settings);
Maybe I'm late to the party, but this also works:
[JsonPropertyName("pname")]
public string? PName { private get; set; }
public string? Name => PName;
You might be able to write a custom JsonConverter to do it with just one Person class, but I'd recommend having separate classes, since the data is modeled differently in the two places. Even if you don't plan to right now, you might find yourself needing to deserialize from Name or serialize to pname at some point. This also allows your classes to differ more substantially. You could use AutoMapper (or similar) to easily convert between the two. E.g.
public class PersonFromThatApi
{
[JsonProperty("pname")]
public string Name { get; set; }
}
public class Person
{
public string Name { get; set; }
}
Mapper.CreateMap<PersonFromThatApi, Person>();
Mapper.CreateMap<Person, PersonFromThatApi>();
var person1 = JsonConvert.DeserializeObject<PersonFromThatApi>(
#"{""pname"":""George""}");
Person person2 = Mapper.Map<Person>(person1);
string s = JsonConvert.SerializeObject(person2); // {"Name":"George"}
And yes, Newtonsoft.Json is the namespace of Json.NET. Don't ask me why they chose totally different names for those two things.
The simple solution is to create two properties.