Saya tahu ada atribut untuk menangani penyetel pribadi tetapi saya ingin perilaku ini sebagai default, apakah ada cara untuk melakukannya? Kecuali mengubah sumbernya. Akan lebih bagus jika ada pengaturan untuk ini.
Jawaban:
Saya datang ke sini mencari atribut sebenarnya yang membuat Json.NET mengisi properti hanya baca saat deserialisasi, dan itu sederhana [JsonProperty], misalnya:
[JsonProperty]
public Guid? ClientId { get; private set; }
Cukup sediakan konstruktor yang memiliki parameter yang cocok dengan properti Anda:
public class Foo
{
public string Bar { get; }
public Foo(string bar)
{
Bar = bar;
}
}
Sekarang ini berhasil:
string json = "{ \"bar\": \"Stack Overflow\" }";
var deserialized = JsonConvert.DeserializeObject<Foo>(json);
Console.WriteLine(deserialized.Bar); // Stack Overflow
Saya lebih suka pendekatan ini jika memungkinkan karena:
{ get; private set; }dan adil { get; }.{get;private set;}, bukan dengan{get;}
{ get; }jika tipe tersebut memiliki konstruktor dengan parameter yang cocok dengan nama properti.
Saya telah menulis distribusi sumber NuGet untuk ini, yang menginstal satu file dengan dua resolver kontrak khusus:
Instal NuGet:
Install-Package JsonNet.PrivateSettersContractResolvers.Source
Kemudian gunakan salah satu resolver:
var settings = new JsonSerializerSettings
{
ContractResolver = new PrivateSetterContractResolver()
};
var model = JsonConvert.DeserializeObject<Model>(json, settings);
Anda dapat membacanya di sini: http://danielwertheim.se/json-net-private-setters-nuget/
Repo GitHub: https://github.com/danielwertheim/jsonnet-privatesetterscontractresolvers
Ada dua alternatif yang bisa mengatasi masalah tersebut.
Alt 1: Di deserializers
ContractResolver.DefaultMembersSearchFlags =
DefaultMembersSearchFlags | BindingFlags.NonPublic;
Opsi serialisasi default mendukung semua jenis anggota kelas. Oleh karena itu, solusi ini akan mengembalikan semua jenis anggota pribadi termasuk bidang. Saya hanya tertarik juga mendukung setter pribadi.
Alt2: Buat ContractResolver kustom:
Oleh karena itu, ini adalah opsi yang lebih baik karena kami baru saja memeriksa properti.
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;
}
}
Untuk informasi lebih lanjut, baca posting saya: http://danielwertheim.se/json-net-private-setters/
DefaultMembersSearchFlagssudah tidak digunakan lagi .
{get; }TIDAK setara dengan { get; private set; }. Untuk cara pertama property.GetSetMethod(true)kembali nulldan yang terakhir true. Ini mengejutkan saya. Anda harus memiliki private set;deserialization untuk bekerja seperti yang diharapkan.
@ Jawaban Daniel (Alt2) tepat, tetapi saya membutuhkan ini untuk bekerja baik untuk penyetel pribadi dan pengambil (saya bekerja dengan API yang sebenarnya memiliki beberapa hal hanya-tulis, seperti user.password.) Inilah yang akhirnya saya dapatkan:
public class NonPublicPropertiesResolver : DefaultContractResolver
{
protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization) {
var prop = base.CreateProperty(member, memberSerialization);
if (member is PropertyInfo pi) {
prop.Readable = (pi.GetMethod != null);
prop.Writable = (pi.SetMethod != null);
}
return prop;
}
}
Terdaftar sebagai berikut:
JsonConvert.DefaultSettings = () => new JsonSerializerSettings {
ContractResolver = new NonPublicPropertiesResolver()
};