Json.net serialize specific private field
There is no need to implement a custom DefaultContractResolver
. The solution is to put [JsonProperty]
on _hexes
and [JsonIgnore]
on all the other properties and fields.
JSON.Net: Force serialization of all private fields and all fields in sub-classes
This should work:
var settings = new JsonSerializerSettings() { ContractResolver = new MyContractResolver() };
var json = JsonConvert.SerializeObject(obj, settings);
public class MyContractResolver : Newtonsoft.Json.Serialization.DefaultContractResolver
{
protected override IList<JsonProperty> CreateProperties(Type type, MemberSerialization memberSerialization)
{
var props = type.GetProperties(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance)
.Select(p => base.CreateProperty(p, memberSerialization))
.Union(type.GetFields(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance)
.Select(f => base.CreateProperty(f, memberSerialization)))
.ToList();
props.ForEach(p => { p.Writable = true; p.Readable = true; });
return props;
}
}
Json.Net ignore serialized private fields in Unity
The problem is that the port of Json.NET that you are using, JilleJr Newtonsoft.Json-for-Unity.Converters, includes a custom contract resolver UnityTypeContractResolver
that includes members marked with [SerializeField]
even when also marked with [JsonIgnore]
. From the source:
protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization)
{
JsonProperty jsonProperty = base.CreateProperty(member, memberSerialization);
// A check for member.GetCustomAttribute<JsonIgnoreAttribute>() is missing in the following line:
if (member.GetCustomAttribute<SerializeField>() != null)
{
jsonProperty.Ignored = false;
jsonProperty.Writable = CanWriteMemberWithSerializeField(member);
jsonProperty.Readable = CanReadMemberWithSerializeField(member);
jsonProperty.HasMemberAttribute = true;
}
return jsonProperty;
}
If you don't want this, you will need to subclass this contract resolver and correct the behavior:
public class FixedUnityTypeContractResolver : Newtonsoft.Json.UnityConverters.UnityTypeContractResolver
{
protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization)
{
JsonProperty jsonProperty = base.CreateProperty(member, memberSerialization);
if (!jsonProperty.Ignored && member.GetCustomAttribute<Newtonsoft.Json.JsonIgnoreAttribute>() != null)
jsonProperty.Ignored = true;
return jsonProperty;
}
}
And then serialize as follows:
// Cache and reuse the contract resolver throughout your project to improve performance.
static Newtonsoft.Json.Serialization.IContractResolver _resolver = new FixedUnityTypeContractResolver ();
var settings = new JsonSerializerSettings
{
ContractResolver = _resolver,
};
JsonConvert.SerializeObject(this, settings);
Get .NET Core JsonSerializer to serialize private members
It seems System.Text.Json does not support private property serialization.
https://learn.microsoft.com/tr-tr/dotnet/standard/serialization/system-text-json-migrate-from-newtonsoft-how-to#internal-and-private-property-setters-and-getters
But as the Microsoft's document says, you can do it with custom converters.
https://www.thinktecture.com/en/asp-net/aspnet-core-3-0-custom-jsonconverter-for-the-new-system_text_json/
Code snippet for serialization & deserialization;
public class Category
{
public Category(List<string> names)
{
this.Names1 = names;
}
private List<string> Names1 { get; set; }
public string Name2 { get; set; }
public string Name3 { get; set; }
}
public class CategoryJsonConverter : JsonConverter<Category>
{
public override Category Read(ref Utf8JsonReader reader,
Type typeToConvert,
JsonSerializerOptions options)
{
var name = reader.GetString();
var source = JsonSerializer.Deserialize<Dictionary<string, JsonElement>>(name);
var category = new Category(null);
var categoryType = category.GetType();
var categoryProps = categoryType.GetProperties(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);
foreach (var s in source.Keys)
{
var categoryProp = categoryProps.FirstOrDefault(x => x.Name == s);
if (categoryProp != null)
{
var value = JsonSerializer.Deserialize(source[s].GetRawText(), categoryProp.PropertyType);
categoryType.InvokeMember(categoryProp.Name,
BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.SetProperty | BindingFlags.Instance,
null,
category,
new object[] { value });
}
}
return category;
}
public override void Write(Utf8JsonWriter writer,
Category value,
JsonSerializerOptions options)
{
var props = value.GetType()
.GetProperties(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance)
.ToDictionary(x => x.Name, x => x.GetValue(value));
var ser = JsonSerializer.Serialize(props);
writer.WriteStringValue(ser);
}
}
static void Main(string[] args)
{
Category category = new Category(new List<string>() { "1" });
category.Name2 = "2";
category.Name3 = "3";
var opt = new JsonSerializerOptions
{
Converters = { new CategoryJsonConverter() },
Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping
};
var json = JsonSerializer.Serialize(category, opt);
var obj = JsonSerializer.Deserialize<Category>(json, opt);
Console.WriteLine(json);
Console.ReadKey();
}
Result;
"{\"Names1\":[\"1\"],\"Name2\":\"2\",\"Name3\":\"3\"}"
Json.Net - Explicitly include a single private property
If you want to serialize/deserialize a privete property, decorate it with the JsonProperty
attribute. Your class should look like this:
public class Customer
{
[JsonProperty]
private string TimeStamp { get; set; }
public Guid CustomerId { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public string Name
{
get
{
return FirstName + " " + LastName;
}
}
public Customer()
{
TimeStamp = DateTime.Now.Ticks.ToString();
}
}
The assumption here is that you initialize the TimeStamp
property in the constructor since it is a private property.
The serialization logic is the following:
var customer = new Customer
{
CustomerId = Guid.NewGuid(),
FirstName = "Jonh",
LastName = "Doe"
};
var json = JsonConvert.SerializeObject(customer, Formatting.Indented);
Console.WriteLine(json);
The output should be similar to the following one:
{
"TimeStamp": "635543531529938160",
"CustomerId": "08537598-73c0-47d5-a320-5e2288989498",
"FirstName": "Jonh",
"LastName": "Doe",
"Name": "Jonh Doe"
}
with the exception of TimeStamp
and CustomerId
properties, that would have different values from obvious reasons.
Private setters in Json.Net
Updated, new answer
I've written a source distribution NuGet for this, that installs a single file with two custom contract resolvers:
- PrivateSetterContractResolver
- PrivateSetterCamelCasePropertyNamesContractResolver
Install the NuGet package:
Install-Package JsonNet.ContractResolvers
Then just use any of the resolvers:
var settings = new JsonSerializerSettings
{
ContractResolver = new PrivateSetterContractResolver()
};
var model = JsonConvert.DeserializeObject<Model>(json, settings);
You can read about it here: http://danielwertheim.se/json-net-private-setters-nuget/
GitHub repo: https://github.com/danielwertheim/jsonnet-privatesetterscontractresolvers
Old answer (still valid)
There are two alternatives that can solve the problem.
Alt 1: On the deserializers
ContractResolver.DefaultMembersSearchFlags =
DefaultMembersSearchFlags | BindingFlags.NonPublic;
The default serialization option supports all types of class member. Therefore this solution will return all private members types including fields. I'm only interested in also supporting private setters.
Alt2: Create a custom ContractResolver:
Therefore this is the better options since we just check the properties.
public class SisoJsonDefaultContractResolver : DefaultContractResolver
{
protected override JsonProperty CreateProperty(
MemberInfo member,
MemberSerialization memberSerialization)
{
//TODO: Maybe cache
var prop = base.CreateProperty(member, memberSerialization);
if (!prop.Writable)
{
var property = member as PropertyInfo;
if (property != null)
{
var hasPrivateSetter = property.GetSetMethod(true) != null;
prop.Writable = hasPrivateSetter;
}
}
return prop;
}
}
For more information, read my post: http://danielwertheim.se/json-net-private-setters/
Related Topics
String Concatenation VS String Builder. Performance
How to Execute Task in the Wpf Background While Able to Provide Report and Allow Cancellation
Identityserver4 Register Userservice and Get Users from Database in ASP.NET Core
What's Better: Dataset or Datareader
Illustrating Usage of the Volatile Keyword in C#
Entity Framework/Sql2008 - How to Automatically Update Lastmodified Fields for Entities
How to Ignore Null Values for All Source Members During Mapping in Automapper 6
Why Isn't My Public Property Serialized by the Xmlserializer
How to Call C# Dll Function from Vbscript
Force Browser to Download PDF Document Instead of Opening It
How to Save Image in Database Using C#
What Are Some Reasons Networkstream.Read Would Hang/Block
How to Wait for Async Method to Complete
Can a Unit Test Project Load the Target Application's App.Config File
How to Specify My Explicit Type Comparator Inline
C# Reflection and Finding All References