我有一个.NET 6解决方案,在调用JsonObject.ToJsonString()时,我试图重写DateTimeOffset的默认格式,这都是使用本机System.Text.Json库。
我添加了一个定制的DateTimeOffsetConverter
public class DateTimeOffsetConverter : JsonConverter<DateTimeOffset>
{
private readonly string _format;
public DateTimeOffsetConverter(string format)
{
_format = format;
}
public override DateTimeOffset Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
Debug.Assert(typeToConvert == typeof(DateTimeOffset));
return DateTimeOffset.Parse(reader.GetString());
}
public override void Write(Utf8JsonWriter writer, DateTimeOffset value, JsonSerializerOptions options)
{
writer.WriteStringValue(value.ToString(_format));
}
public override bool CanConvert(Type typeToConvert)
{
return (typeToConvert == typeof(DateTimeOffset));
}
}但是,当我尝试使用它时,除了调用构造函数之外,代码永远不会被击中。
我错过了什么阻止JsonConverter被调用的东西?
下面是我的代码,它试图利用这些功能:
[Theory]
[InlineData("New Zealand Standard Time")]
[InlineData("India Standard Time")]
[InlineData("Central Brazilian Standard Time")]
[InlineData("W. Australia Standard Time")]
public void DateTimeOffsetIsSerializedCorrectlyTest(string timeZoneId)
{
const string DateTimeFormat = "yyyy-MM-ddTHH:mm:ss.fffzzz";
var timeZoneInfo = TimeZoneInfo.FindSystemTimeZoneById(timeZoneId);
var dateTimeOffset = new DateTimeOffset(DateTimeOffset.Now.DateTime, timeZoneInfo.BaseUtcOffset);
var json = new JsonObject
{
{ "value", dateTimeOffset }
};
var options = new JsonSerializerOptions
{
Converters = { new DateTimeOffsetConverter(DateTimeFormat) }
};
string jsonString = json.ToJsonString(options);
Assert.Contains(jsonString, dateTimeOffset.ToString(DateTimeFormat));
}有许多密切相关的问题已经张贴,谁的解决方案,我已经试验过,但似乎没有解决我的确切情况。
发布于 2022-11-27 16:10:05
似乎在DateTimeOffset转换为时应用了转换器,而不是当JsonNode被格式化为string时。因此,您可以通过显式序列化 (您的DateTimeOffset )生成所需的JSON,而不是依赖于隐式转换
var options = new JsonSerializerOptions
{
Converters = { new DateTimeOffsetConverter(DateTimeFormat) }
};
var json = new JsonObject
{
{ "value", JsonSerializer.SerializeToNode(dateTimeOffset, options) }
};这导致了{"value":"2022-11-27T15:10:23.570\u002B12:00"}。注意,+是转义的。如果您要求它不被转义以使您的Assert.Contains(jsonString, dateTimeOffset.ToString(DateTimeFormat));成功通过,请使用UnsafeRelaxedJsonEscaping
var formattingOptions = new JsonSerializerOptions
{
Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping,
// Other formatting options as required, e.g.
//WriteIndented = true, // This option also seems to be applied when the JsonNode is formatted to a string, rather than when it is constructed
};
string jsonString = json.ToJsonString(formattingOptions);这导致了{"value":"2022-11-27T15:17:44.142+12:00"}。
演示小提琴#1 这里。
备注:
JsonSerializerOptions声明:
可以使用JsonSerializer序列化和反序列化JsonNode实例。但是,如果使用采用JsonSerializerOptions的重载,则选项实例仅用于获取自定义转换器。没有使用选项实例的其他功能。..。这条语句似乎不正确;即使用DateTimeOffsetConverter序列化JsonNode层次结构,也不会提取您的JsonSerializer.Serialize(json, options)。
演示小提琴#2 这里。
JsonNode构造和JsonNode字符串格式化过程中应用的选项。文档确实显示了在字符串格式设置期间应用。。一些实验表明,此外,在字符串格式化过程中还应用了Encoder和(令人惊讶的) NumberHandling。
演示小提琴#3 这里。DateTimeOffsetConverter。隐式转换算子:
JsonNode节点= dateTimeOffset;
返回类型为JsonValueTrimmable的对象。这种类型包括它自己的内部转换器:
内部密封部分类JsonValueTrimmable : JsonValue {专用只读JsonTypeInfo?_jsonTypeInfo;私有只读JsonConverter?_converter;
如果我们使用反射访问_converter的值,我们会发现它被初始化为系统转换器DateTimeOffsetConverter:
Console.WriteLine("JsonValueTrimmable._converter = {0}",fi.GetValue(节点));//打印System.Text.Json.Serialization.Converters.DateTimeOffsetConverter
此系统转换器忽略传入选项,只需调用Utf8JsonWriter.WriteStringValue(DateTimeOffset);。
演示小提琴#4 这里。https://stackoverflow.com/questions/74484057
复制相似问题