C# 用于在Blazor和JS之间传递DateTimeOffset的自定义Json转换器。JS属性输入/输出是不同的类型
我有一个场景,我必须将C# 用于在Blazor和JS之间传递DateTimeOffset的自定义Json转换器。JS属性输入/输出是不同的类型,c#,json,blazor,system.text.json,blazor-jsinterop,C#,Json,Blazor,System.text.json,Blazor Jsinterop,我有一个场景,我必须将DateTimeOffset序列化为一个简单的字符串值(例如“2021-04-07T18:18:00.000Z”,但将其反序列化为嵌入对象中的值(例如{u date:“2021-04-07T18:18:00.000Z”})。如何使用System.Text.JSON 详细信息如下。我正在为blazor包装一个。我已经用C#类包装了JS类。当从blazor向JS发送日历“日程表”(事件)时,日期时间只是作为序列化字符串传递。这很有效 当从JS向Blazor发送“schedule
DateTimeOffset
序列化为一个简单的字符串值(例如“2021-04-07T18:18:00.000Z”
,但将其反序列化为嵌入对象中的值(例如{u date:“2021-04-07T18:18:00.000Z”}
)。如何使用System.Text.JSON
详细信息如下。我正在为blazor包装一个。我已经用C#类包装了JS类。当从blazor向JS发送日历“日程表”(事件)时,日期时间只是作为序列化字符串传递。这很有效
当从JS向Blazor发送“schedule”时,它会作为一个对象(TZdate)返回,内部是一个“_date”属性
返回的json对象如下所示:
{
"end":{
"_date":"2021-04-07T18:18:00.000Z"
}
}
我已尝试为DateTimeOffset编写自定义转换器。以下是读取方法:
public覆盖DateTimeOffset读取(
参考Utf8JsonReader读取器,
类型转换,
JsonSerializerOptions选项)=>
DateTimeOffset.ParseExact(JsonDocument.Parse(reader.GetString()).RootElement.EnumerateObject().First().Value.EnumerateObject().First().Value.GetString(),
TZDateFormat,CultureInfo.InvariantCulture);
上述方法不起作用。我认为我没有正确使用reader
类,也不知道如何从json中提取“\u date”
或者,我尝试用一个新的“TZDate”类和一个属性“_date”包装我的DateTimeOffset属性,但这在JS端中断了,因为库希望从C#得到一个简单的datetime字符串,而不是一个对象
更改JS库可能不是一个选项
我的选项是什么,或者如何解决这个问题?您的
DateTimeOffset
值嵌入到一个对象中,如下所示:
{u date:“2021-04-07T18:18:00.000Z”}
您希望提取要返回的内部\u date
属性的值。您可以使用以下JsonConverter.Read()
方法执行此操作:
public class DateTimeOffsetConverter : JsonConverter<DateTimeOffset>
{
const string TZDateFormat = "O"; // Your custom format (not shown in your question).
public override void Write(Utf8JsonWriter writer, DateTimeOffset value, JsonSerializerOptions options) =>
// Write as a simple string.
writer.WriteStringValue(value.ToString(TZDateFormat, CultureInfo.InvariantCulture));
const string _date = "_date";
public override DateTimeOffset Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
switch (reader.TokenType)
{
case JsonTokenType.String:
// A simple DateTimeOffset string "value"
return DateTimeOffset.ParseExact(reader.GetString(), TZDateFormat, CultureInfo.InvariantCulture);
case JsonTokenType.StartObject:
{
// A DateTimeOffset string embedded in an object { "_date" : "value" }
using var doc = JsonDocument.ParseValue(ref reader);
if (doc.RootElement.TryGetProperty(_date, out var value))
return DateTimeOffset.ParseExact(value.GetString(), TZDateFormat, CultureInfo.InvariantCulture);
return default(DateTimeOffset); // Or throw an exception?
}
default:
throw new JsonException(); // Unknown token type
}
}
}
这有点复杂,但也应该更有效
在这两种情况下,我都会检查传入值是对象还是简单字符串。如果是简单字符串,我会继续将其解析为DateTimeOffset
演示小提琴。回答和细节都很好。谢谢。这就是我想要做的。我昨晚的工作是制作两个转换器。一个用于DateTimeOffset,另一个用于TzDate类/对象。TzDate对象写入方法只需将_date属性作为字符串输出,读取返回带有_date属性的对象y、 额外的层和笨重。我将实现您在这里详细介绍的内容。
static byte [] _date = Encoding.UTF8.GetBytes("_date");
public override DateTimeOffset Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
switch (reader.TokenType)
{
case JsonTokenType.String:
// A simple DateTimeOffset string "value"
return DateTimeOffset.ParseExact(reader.GetString(), TZDateFormat, CultureInfo.InvariantCulture);
case JsonTokenType.StartObject:
{
// A DateTimeOffset string embedded in an object { "_date" : "value" }
DateTimeOffset? value = null;
while (reader.Read())
{
switch (reader.TokenType)
{
case JsonTokenType.EndObject:
return value.GetValueOrDefault();
case JsonTokenType.PropertyName:
var match = reader.ValueTextEquals(_date);
reader.Read();
if (match)
value = DateTimeOffset.ParseExact(reader.GetString(), TZDateFormat, CultureInfo.InvariantCulture);
else
reader.Skip();
break;
default:
throw new JsonException();
}
}
}
break;
}
throw new JsonException();
}