1

I have the following code for model:

public class Sensor
{
    public long Id { get; set; }
    [Required]
    public string Tag { get; set; }
    public DateTime Timestamp { get; set; }
    public string Status { get; set; }
    public int Valor { get; set; }
}

I am receiving this by an WebAPI Controller, by POST method.

This is the signature for the POST method:

public async Task<ActionResult<Sensor>> PostSensor(Sensor sensor)

It receives values like this example:

{
    "tag": "mytag",
    "Timestamp": "1575179924",
    "valor": "3000"
}

My problem is that due to the Controller's signature, it tries to validate the timestamp, and fails because the UNIX Timestamp isn't the DateTime one.

I wanted to convert it inside this method, but this would require disabling validation for the whole Controller.

I tried creating a JSON Converter, but it always fails to convert.

public class UnixEpochTimeToDateTimeConverter: Newtonsoft.Json.JsonConverter
{
    public override bool CanWrite => false;

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

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue,
        JsonSerializer serializer)
    {
        if (!reader.Path.ToLower().Contains("time")) return null;
        var parsed = long.TryParse(reader.Value.ToString(), out var unixTimeStamp);
        if(!parsed){ return null; }
        var epoch = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);
        var timeSpan = TimeSpan.FromSeconds(unixTimeStamp);
        var localDateTime = epoch.Add(timeSpan).ToLocalTime();

        return localDateTime;
    }

    public override bool CanConvert(Type objectType)
    {
        return objectType == typeof(DateTime);
    }
}

(I get this error: The JSON value could not be converted to System.DateTime. Path: $.Timestamp)

Is there a solution for this? Maybe another way to convert it? (I really don't know if i am doing anything wrong)

Pavel Anikhouski
  • 21,776
  • 12
  • 51
  • 66
Alexander Santos
  • 1,458
  • 11
  • 22
  • 2
    Remark: are you aware of [DateTimeOffset.FromUnixTimeSeconds](https://learn.microsoft.com/en-us/dotnet/api/system.datetimeoffset.fromunixtimeseconds)? – Klaus Gütter Dec 01 '19 at 07:03
  • Yes, i saw some implementation of this method while Googling around, but for some reason it still fails. As a workaround i have created a "UnixSensor" model class, which receives the tag, timestamp and valor. I disabled the automatic validation and did the conversion by hand (Converting and transferring the UnixSensor's data to Sensor's model and then saving at database/replying client). This sounds like a very ugly approach though, not sure if it's the only way to do it. – Alexander Santos Dec 01 '19 at 07:12
  • Of course this does not solve your problem, it was just a remark that this would be a built-in alternative to the DateTime/TimeSpan math in your code. – Klaus Gütter Dec 01 '19 at 07:14
  • 1
    Doesn't [this](https://www.newtonsoft.com/json/help/html/T_Newtonsoft_Json_Converters_UnixDateTimeConverter.htm) already do what you're trying to do? – sellotape Dec 01 '19 at 09:57
  • I also tried using this converter as annotation for the timestamp, it was giving me the same error as the converter i wrote. – Alexander Santos Dec 01 '19 at 15:11
  • I've used it and it works perfectly. So your model has a DateTime property annotated with a JsonConverter attribute which has a typeof(UnixDateTimeConverter) parameter? Are you sure the values are in seconds since the epoch and not milliseconds? – sellotape Dec 01 '19 at 15:24
  • Yes, when i did it disabling the validation and converting inside controller it works. Not sure about how this built-in JsonConverter isn't working though, i wrote it the same way as [this answer](https://stackoverflow.com/a/48980715/10473393) does. – Alexander Santos Dec 01 '19 at 16:49

1 Answers1

2

Don't fight the format, just allow Timestamp to be a long. There's no reason you can't convert the Timestamp to whatever format you need by calling a property on the Sensor object.

public class Sensor
{
    public long Id { get; set; }

    [Required]
    public string Tag { get; set; }

    public long Timestamp { get; set; }

    public DateTime TimestampDt
    { 
        get
        {
            return DateTimeOffset.FromUnixTimeSeconds(Timestamp).UtcDateTime;
        }
    }

    public string Status { get; set; }

    public int Valor { get; set; }
}
robbpriestley
  • 3,050
  • 2
  • 24
  • 36