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