Я получаю JSON из веб-запроса, который я хотел бы десериализовать в следующий класс:

public class MyData
{
   public int id { get; set; }
   public DateTime openTime { get; set; }
   MyData() {}
}

Это JSON, который я получаю от сервера:

var json= @"{""Id"": ""12345"",""openTime"":""2015-09-01T12:00:00:000Z""}"

Насколько я могу судить, эта строка DateTime соответствует стандарту ISO 8601, но я не понимаю, почему в конце есть три 0 для миллисекунд и дополнительный Z. Вот как я пытаюсь преобразовать строку в свой объект:

var responseInstance = JsonConvert.DeserializeObject<MyData>(json,new IsoDateTimeConverter());

Это вызывает System.FormatException: String не был распознан как допустимый DateTime.

Когда я пытаюсь добавить JsonSerializerSetting вместо IsoDateTimeConverter следующим образом:

var deserializeSetting = new JsonSerializerSettings()
{
   DateFormatHandling = DateFormatHandling.IsoDateFormat
};
var responseInstance = JsonConvert.DeserializeObject<MyData>(json,deserializeSetting);

Исключение не генерируется, но вместо этого элемент datetime всегда показывает 01.01.0001 00:00:00

4
zlZimon 16 Окт 2015 в 17:06

3 ответа

Лучший ответ

Проблема в том, что ваша строка даты неправильно отформатирована. Между секундами и миллисекундами должен быть символ точки (.), а не двоеточие (:). Json.Net использует DateTime.Parse внутри для анализа дат. Если он терпит неудачу, он молча поглощает ошибку, и дата никогда не устанавливается на вашем объекте. Таким образом, вы получите дату по умолчанию 01/01/0001 00:00:00.

ИЗМЕНИТЬ

Если вы не можете изменить JSON (например, потому что он контролируется третьей стороной), вы можете использовать специальный конвертер JSON, чтобы разрешить правильную десериализацию плохого формата.

class BadDateFixingConverter : JsonConverter
{
    public override bool CanConvert(Type objectType)
    {
        return (objectType == typeof(DateTime) || objectType == typeof(DateTime?));
    }

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        string rawDate = (string)reader.Value;
        DateTime date;

        // First try to parse the date string as is (in case it is correctly formatted)
        if (DateTime.TryParse(rawDate, out date))
        {
            return date;
        }

        // If not, see if the string matches the known bad format. 
        // If so, replace the ':' with '.' and reparse.
        if (rawDate.Length > 19 && rawDate[19] == ':')
        {
            rawDate = rawDate.Substring(0, 19) + '.' + rawDate.Substring(20);
            if (DateTime.TryParse(rawDate, out date))
            {
                return date;
            }
        }

        // It's not a date after all, so just return the default value
        if (objectType == typeof(DateTime?)) 
            return null;

        return DateTime.MinValue;
    }

    public override bool CanWrite
    {
        get { return false; }
    }

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        throw new NotImplementedException();
    }
}

Используйте это так:

JsonSerializerSettings settings = new JsonSerializerSettings
{
    Converters = new List<JsonConverter> { new BadDateFixingConverter() },
    DateParseHandling = DateParseHandling.None
};

MyData obj = JsonConvert.DeserializeObject<MyData>(json, settings);

Скрипка: https://dotnetfiddle.net/M1w36e

7
Brian Rogers 16 Окт 2015 в 15:36
var deserializeSetting = new JsonSerializerSettings()
{
    DateTimeFormat = new System.Runtime.Serialization.DateTimeFormat("o")
};

Это должно сработать, или попробуйте Newtonsoft librarie, которая просто великолепна.

-1
Xavier W. 16 Окт 2015 в 14:08
class BadDateFixingConverter : JsonConverter
{
    string FormatStringVaue;
    public BadDateFixingConverter(string FormatString)
    {
        this.FormatStringVaue = FormatString;
    }
    public override bool CanConvert(Type objectType)
    {
        return (objectType == typeof(DateTime) || objectType == typeof(DateTime?));
    }

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        string rawDate = (string)reader.Value;

        try
        {
            return DateTime.ParseExact(rawDate, FormatStringVaue, null);
        }
        catch
        {
            // It's not a date after all, so just return the default value
            if (objectType == typeof(DateTime?))
                return null;

            return DateTime.MinValue;

        }
    }

    public override bool CanWrite
    {
        get { return false; }
    }

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        throw new NotImplementedException();
    }
}

Используйте это так:

       JsonSerializerSettings settings = new JsonSerializerSettings
        {
            Converters = new List<JsonConverter> {new BadDateFixingConverter("yyyyMMddHHmmss") },
            DateParseHandling = DateParseHandling.None
        };
4
Valeh Mikayilzadeh 12 Авг 2016 в 14:04