获取 .NET Core JsonSerializer 以序列化私有成员

Posted

技术标签:

【中文标题】获取 .NET Core JsonSerializer 以序列化私有成员【英文标题】:Get .NET Core JsonSerializer to serialize private members 【发布时间】:2020-09-04 05:45:12 【问题描述】:

我有一个带有私有List<T> 属性的类,我想使用JsonSerializer 对其进行序列化/反序列化。 .NET Core 似乎不支持使用 JsonPropertyAttribute。那么我怎样才能序列化我的私有列表属性呢?

我为此使用 System.Text.Json。

【问题讨论】:

您使用的是 Newtonsoft.Json 还是 System.Text.Json? 已序列化但未反序列化?添加一个只读的公共属性,在获取时返回您的私有列表。 @HereticMonkey 我正在使用 System.Text.Json。将此添加到问题中。 System.Text.Json 不支持内部和private getters and setters out of the box 仅供参考:github.com/dotnet/runtime/pull/34675 【参考方案1】:

System.Text.Json 好像不支持私有属性序列化。

https://docs.microsoft.com/tr-tr/dotnet/standard/serialization/system-text-json-migrate-from-newtonsoft-how-to#internal-and-private-property-setters-and-getters

但正如微软的文档所说,您可以使用自定义转换器来做到这一点。

https://www.thinktecture.com/en/asp-net/aspnet-core-3-0-custom-jsonconverter-for-the-new-system_text_json/

序列化的代码sn-p;

  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();
    

结果;

"\"Names1\":[\"1\"],\"Name2\":\"2\",\"Name3\":\"3\""

【讨论】:

我已经阅读了这篇文章,但我不确定这是否会帮助我序列化/反序列化私有属性。在我看来,自定义 JsonConverter 似乎允许我重写 how 某个属性是序列化的,但不是 if (如果是私有属性,情况并非如此)。如果我错了,请纠正我。 @Mats - 您不为属性编写转换器,而是为 整个对象 编写转换器并通过转换器手动序列化它(包括所有私有字段) . @Mats 我认为这篇文章可能对你有所帮助,我没有深入挖掘它。并用一些用于序列化的代码 sn-p 更新我的答案,它可能会引导你走得更远,因为除了你的方式之外没有其他办法(System.Text Json 不提供):) @anilcemsimsek 哦,你是对的!我得到了那个工作。为了使它对下一个有同样问题的人有用且完整的答案,我想请您提供一些反序列化示例。你知道为什么 JSON 输出的所有引号都被转义了吗?而不是 \"Names1\": ... 我认为应该是 "Names1":...。我尝试摆弄 JavascriptEncoder 但无济于事。 @Mats 好的,我用代码 sn-p 更新了我的答案以进行反序列化。请检查您的问题是否可以。【参考方案2】:

System.Text.Json 根据micosoft documentation支持从.NET 5 开始的私有属性序列化

System.Text.Json 通过 [JsonInclude] 属性支持私有和内部属性设置器和获取器。Find more details here

【讨论】:

对我不起作用:'The non-public property 'TenantsSource' on type '...SubscriptionModel' is annotated with 'JsonIncludeAttribute' which is invalid.'。看起来 [JsonInclude] 在 getter 或 setter 都是私有的情况下有效,但如果两者都是私有的,则无效。 老实说,我不喜欢在域模型上使用此类属性。对于此类私有模型序列化,我们仍在使用 Newtonsoft json。

以上是关于获取 .NET Core JsonSerializer 以序列化私有成员的主要内容,如果未能解决你的问题,请参考以下文章

获取 ASP.NET-Core 2.2 控制器中的控制器名称和方法名称

.net core获取appsettings CustomSettings

.net core 静态类获取appsettings

ASP.NET Core DI 手动获取注入对象

ASP.Net Core 如何在 EF Core 和 Identity 中获取用户角色

csharp ASP.NET Core-获取所有注入(DI)服务