Joh*_*ika 15 c# json.net .net-core asp.net-core system.text.json
使用 .Net Core 3 的新 System.Text.Json JsonSerializer,如何自动转换类型(例如 int 到 string 和 string 到 int)?例如,这会引发异常,因为id在 JSON 中是数字,而在 C# 中需要Product.Id一个字符串:
public class HomeController : Controller
{
public IActionResult Index()
{
var json = @"{""id"":1,""name"":""Foo""}";
var o = JsonSerializer.Deserialize<Product>(json, new JsonSerializerOptions
{
PropertyNameCaseInsensitive = true,
});
return View();
}
}
public class Product
{
public string Id { get; set; }
public string Name { get; set; }
}
Run Code Online (Sandbox Code Playgroud)
Newtonsoft 的 Json.Net 很好地处理了这个问题。如果您在 C# 期望字符串时传入数值并不重要(反之亦然),一切都按预期反序列化。如果您无法控制作为 JSON 传入的类型格式,您如何使用 System.Text.Json 处理此问题?
itm*_*nus 17
新的System.Text.Jsonapi 公开了一个JsonConverterapi,它允许我们根据需要转换类型。
例如,我们可以创建一个通用number的string转换器:
public class AutoNumberToStringConverter : JsonConverter<object>
{
public override bool CanConvert(Type typeToConvert)
{
return typeof(string) == typeToConvert;
}
public override object Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
if(reader.TokenType == JsonTokenType.Number) {
return reader.TryGetInt64(out long l) ?
l.ToString():
reader.GetDouble().ToString();
}
if(reader.TokenType == JsonTokenType.String) {
return reader.GetString();
}
using(JsonDocument document = JsonDocument.ParseValue(ref reader)){
return document.RootElement.Clone().ToString();
}
}
public override void Write(Utf8JsonWriter writer, object value, JsonSerializerOptions options)
{
writer.WriteStringValue( value.ToString());
}
}
Run Code Online (Sandbox Code Playgroud)当使用 MVC/Razor Page 时,我们可以在启动时注册这个转换器:
services.AddControllersWithViews().AddJsonOptions(opts => {
opts.JsonSerializerOptions.PropertyNameCaseInsensitive= true;
opts.JsonSerializerOptions.Converters.Insert(0, new AutoNumberToStringConverter());
});
Run Code Online (Sandbox Code Playgroud)
然后 MVC/Razor 将自动处理类型转换。
或者,如果您想手动控制序列化/反序列化:
var opts = new JsonSerializerOptions {
PropertyNameCaseInsensitive = true,
};
opts.Converters.Add(new AutoNumberToStringConverter());
var o = JsonSerializer.Deserialize<Product>(json,opts) ;
Run Code Online (Sandbox Code Playgroud)以类似的方式,您可以启用字符串到数字类型的转换,如下所示:
public class AutoStringToNumberConverter : JsonConverter<object>
{
public override bool CanConvert(Type typeToConvert)
{
// see https://stackoverflow.com/questions/1749966/c-sharp-how-to-determine-whether-a-type-is-a-number
switch (Type.GetTypeCode(typeToConvert))
{
case TypeCode.Byte:
case TypeCode.SByte:
case TypeCode.UInt16:
case TypeCode.UInt32:
case TypeCode.UInt64:
case TypeCode.Int16:
case TypeCode.Int32:
case TypeCode.Int64:
case TypeCode.Decimal:
case TypeCode.Double:
case TypeCode.Single:
return true;
default:
return false;
}
}
public override object Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
if(reader.TokenType == JsonTokenType.String) {
var s = reader.GetString() ;
return int.TryParse(s,out var i) ?
i :
(double.TryParse(s, out var d) ?
d :
throw new Exception($"unable to parse {s} to number")
);
}
if(reader.TokenType == JsonTokenType.Number) {
return reader.TryGetInt64(out long l) ?
l:
reader.GetDouble();
}
using(JsonDocument document = JsonDocument.ParseValue(ref reader)){
throw new Exception($"unable to parse {document.RootElement.ToString()} to number");
}
}
public override void Write(Utf8JsonWriter writer, object value, JsonSerializerOptions options)
{
var str = value.ToString(); // I don't want to write int/decimal/double/... for each case, so I just convert it to string . You might want to replace it with strong type version.
if(int.TryParse(str, out var i)){
writer.WriteNumberValue(i);
}
else if(double.TryParse(str, out var d)){
writer.WriteNumberValue(d);
}
else{
throw new Exception($"unable to parse {str} to number");
}
}
}
Run Code Online (Sandbox Code Playgroud)Svj*_*Man 13
您可以在模型类中使用JsonNumberHandlingAttribute来指定如何处理数字反序列化。允许的选项在JsonNumberHandling枚举中指定。
使用示例:
public class Product
{
[JsonNumberHandling(JsonNumberHandling.WriteAsString)]
public string Id { get; set; }
public string Name { get; set; }
}
Run Code Online (Sandbox Code Playgroud)
如果需要序列化 from stringto int,可以使用JsonNumberHandling.AllowReadingFromString
mar*_*sze 12
在选项中,将NumberHandling属性设置为AllowReadingFromString:
var o = JsonSerializer.Deserialize<Product>(json, new JsonSerializerOptions
{
// [...]
NumberHandling = JsonNumberHandling.AllowReadingFromString
});
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
13161 次 |
| 最近记录: |