Имеется json:
{
"access_token": "xxx",
"token_type": "bearer",
"expires_in": 86400,
"refresh_token": "yyy",
"created_at": 1524344276
}
created_at возвращает время в секундах от 1970 года, поэтому модель для этого json написал следующую:
public class OAuth2Token
{
[JsonProperty("access_token")]
public string AccessToken { get; }
[JsonProperty("token_type")]
public string TokenType { get; }
[JsonProperty("expires_in")]
public int ExpiresIn { get; } //Seconds
[JsonProperty("refresh_token")]
public string RefreshToken { get; }
[JsonProperty("created_at"), JsonConverter(typeof(SecondEpochConverter))]
public DateTime CreatedAt { get; }
}
И для конвертации секунд в DateTime использую конвертер:
public class SecondEpochConverter : DateTimeConverterBase
{
private static readonly DateTime _epoch = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
writer.WriteRawValue(((DateTime)value - _epoch).TotalSeconds.ToString());
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
if (reader.Value == null) { return null; }
return _epoch.AddSeconds((long)reader.Value);
}
}
Однако при попытке распарсить срабатывает исключение:
JsonReaderException: Unexpected character encountered while parsing value: 1. Path 'created_at', line 1, position 221.
UPD:
Для работы с автоматическими свойствами без сеттеров установлена следующая настройка:
jsonSerializerSettings = new JsonSerializerSettings //for (de-)serialization get-autoproperty
{
ContractResolver = new PrivateSetterContractResolver()
};
(Github и NuGet решения) и вызывается десериализация вот так:
//T - в данном случае OAuth2Token
JsonConvert.DeserializeObject<T>(response, jsonSerializerSettings);
Вы забыли сеттеры.
Рабочий пример:
void Main()
{
var source = @"{
""access_token"": ""xxx"",
""token_type"": ""bearer"",
""expires_in"": 86400,
""refresh_token"": ""yyy"",
""created_at"": 1524344276
}";
var result = JsonConvert.DeserializeObject<OAuth2Token>(source);
result.Dump();
}
// Define other methods and classes here
public class SecondEpochConverter : JsonConverter
{
private static readonly DateTime _epoch = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
writer.WriteRawValue(((DateTime)value - _epoch).TotalSeconds.ToString());
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
if (reader.Value == null) { return null; }
return _epoch.AddSeconds((long)reader.Value);
}
public override bool CanConvert(Type objectType)
{
throw new NotImplementedException();
}
}
public class OAuth2Token
{
[JsonProperty("access_token")]
public string AccessToken { get; set; }
[JsonProperty("token_type")]
public string TokenType { get; set; }
[JsonProperty("expires_in")]
public int ExpiresIn { get; set; } //Seconds
[JsonProperty("refresh_token")]
public string RefreshToken { get; set; }
[JsonProperty("created_at")]
[JsonConverter(typeof(SecondEpochConverter))]
public DateTime CreatedAt { get; set; }
}
Вывод:
(Если заменить JsonConverter обратно на DateTimeConverterBase и убрать CanConvert - тоже будет работать)
С учётом вскрывшихся подробностей. Посмотрите пример:
var settings = new JsonSerializerSettings
{
ContractResolver = new PrivateSetterContractResolver()
};
var model = JsonConvert.DeserializeObject<Model>(json, settings);
где модель:
public class Model
{
public string Value { get; private set; }
}
That's it.
PS Можно поставить только на одно это свойство с кастомным конвертером.
Сборка персонального компьютера от Artline: умный выбор для современных пользователей