Xor*_*ist 5 json constructor .net-5 system.text.json
给定 Base64 字符串,以下示例类将使用Newtonsoft.Json正确反序列化,但不能使用System.Text.Json:
using System;
using System.Text.Json.Serialization;
public class AvatarImage{
public Byte[] Data { get; set; } = null;
public AvatarImage() {
}
[JsonConstructor]
public AvatarImage(String Data) {
//Remove Base64 header info, leaving only the data block and convert it to a Byte array
this.Data = Convert.FromBase64String(Data.Remove(0, Data.IndexOf(',') + 1));
}
}
Run Code Online (Sandbox Code Playgroud)
对于 System.Text.Json,会引发以下异常:
must bind to an object property or field on deserialization. Each parameter name must match with a property or field on the object. The match can be case-insensitive.
Run Code Online (Sandbox Code Playgroud)
显然 System.Text.Json 不喜欢属性是 Byte[] 但参数是 String,这并不重要,因为重点是构造函数应该处理赋值。
有什么方法可以让它与 System.Text.Json 一起使用吗?
在我的特定情况下,Base64 图像被发送到 WebAPI 控制器,但最终对象只需要 Byte[]。在 Newtonsoft 中,这是一个快速而干净的解决方案。
dbc*_*dbc 10
这显然是 的已知限制System.Text.Json。查看问题:
因此(至少在 .Net 5 中)您将需要重构您的类以避免限制。
一种解决方案是添加代理 Base64 编码字符串属性:
public class AvatarImage
{
[JsonIgnore]
public Byte[] Data { get; set; } = null;
[JsonInclude]
[JsonPropertyName("Data")]
public string Base64Data
{
private get => Data == null ? null : Convert.ToBase64String(Data);
set
{
var index = value.IndexOf(',');
this.Data = Convert.FromBase64String(index < 0 ? value : value.Remove(0, index + 1));
}
}
}
Run Code Online (Sandbox Code Playgroud)
请注意,通常JsonSerializer只会序列化公共属性。但是,如果您使用setter或getter标记属性,[JsonInclude]则setter或getter(但不能同时使用两者)都可以是非公共的。(我不知道为什么微软不允许两者都是私有的,数据契约序列化程序当然支持标有 的私有成员。)在这种情况下,我选择将 getter 设置为私有,以减少代理属性被其他一些序列化的机会序列化器或通过某些属性浏览器显示。[DataMember]
演示小提琴#1在这里。
或者,您可以引入一个自定义JsonConverter<T>AvatarImage
[JsonConverter(typeof(AvatarConverter))]
public class AvatarImage
{
public Byte[] Data { get; set; } = null;
}
class AvatarConverter : JsonConverter<AvatarImage>
{
class AvatarDTO { public string Data { get; set; } }
public override AvatarImage Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
var dto = JsonSerializer.Deserialize<AvatarDTO>(ref reader, options);
var index = dto.Data?.IndexOf(',') ?? -1;
return new AvatarImage { Data = dto.Data == null ? null : Convert.FromBase64String(index < 0 ? dto.Data : dto.Data.Remove(0, index + 1)) };
}
public override void Write(Utf8JsonWriter writer, AvatarImage value, JsonSerializerOptions options) =>
JsonSerializer.Serialize(writer, new { Data = value.Data }, options);
}
Run Code Online (Sandbox Code Playgroud)
对于简单模型来说,这似乎是更简单的解决方案,但对于复杂模型或经常添加属性的模型来说,这可能会成为麻烦。
演示小提琴#2在这里。
最后,似乎有点不幸的是,该Data属性在反序列化期间会预先添加一些在序列化期间不存在的额外标头。不要在反序列化期间修复此问题,而是考虑修改架构以避免Data首先损坏字符串。
| 归档时间: |
|
| 查看次数: |
3946 次 |
| 最近记录: |