0

In ASP.NET WebApi: I have a DTO class:

public class DTO
{
    public string Date {get; set;}
}

when the client (an Internet Explorer plugin) requests data from this WebApi, I return IEnumerable<DTO> like this:

return Request.CreateResponse(System.Net.HttpStatusCode.OK, dtoObject)

Where dtoObject is of type IEnumerable<DTO>. While debugging, I check the value of dtoObject[0].Date and it shows 22-Nov-18 12:00:00 AM, and this is the expected value.

In the Internet Explorer plugin: I have a model class called Model:

public class Model
{
    public string Date {get; set;}
}

I request the WebApi Like this:

var response = await httpClient.PostAsJsonAsync(serviceUrl, requestDto);
var returnJson = await response.Content.ReadAsStringAsync();
var result = JsonConvert.DeserializeObject<IEnumerable<Model>>(returnJson)

Now, when I check result[0].Date I get, 12/11/2018 12:00:00 AM while I am expecting 22-Nov-18 12:00:00 AM

I have read that date values are serialized differently by different libraries/languages.. But, I am using a string to store the value then why is the value getting changed? I want to receive the Date value in dd-MMM-yy hh:mm:ss tt format. How do I achieve that?

ravi kumar
  • 1,548
  • 1
  • 13
  • 47
  • 2
    you really should include enough code, so that we readers, can reproduce the result. This problem could be a number of things. Culture override, format override. etc. You really just need to entity.DateTimeProperty.ToString("mm/dd/yyyy"). Could also be that the other hoster simply configured the data to be in this format, and you must now parse that data on your side. – Morten Bork Nov 20 '18 at 08:11
  • A string containing a date won't change its format when transferred through JSON. It's your display logic that does this. – CodeCaster Nov 20 '18 at 09:23
  • I don't have a display logic. I debug my plugin and see `entity.date` and I get `"07/11/2018 12:00:00 AM"` – ravi kumar Nov 20 '18 at 09:26
  • Is it worth using a deserialisation date formatter? https://stackoverflow.com/questions/21256132/deserializing-dates-with-dd-mm-yyyy-format-using-json-net See @Foy 's answer. Same as Rebecca's answer below in this question, but it's local, not global. – Dan Rayson Nov 22 '18 at 13:58
  • Can you please [edit] your question to share the value of the string `returnJson`? – dbc Nov 22 '18 at 17:18
  • It looks like this issue explains why you got a different string: https://github.com/JamesNK/Newtonsoft.Json/issues/862 – CSakura Nov 23 '18 at 15:28

2 Answers2

3

The stated problem is unable to be reproduced in the following tests.

A unit test that serializes a DTO and then deserializes a Model behaves as expected

[Test]
public void __String_Dates_Should_Match() {
    //Arrange
    var date = "22-Nov-18 12:00:00 AM";
    var dtoObject = new[] { new DTO { Date = date } };
    var returnJson = JsonConvert.SerializeObject(dtoObject);

    //Act
    var result = JsonConvert.DeserializeObject<IEnumerable<Model>>(returnJson);

    //Assert
    result.First()
        .Should().NotBeNull()
        .And.Match<Model>(_ => _.Date == date);
}

An integration test using in-memory Web API also behaves as expected

[TestClass]
public class MyTestClass {
    [Test]
    public async Task __WebApi_Dates_Should_Match() {
        //Arrange
        var date = "22-Nov-18 12:00:00 AM";
        var config = new HttpConfiguration();
        config.MapHttpAttributeRoutes();
        var httpServer = new HttpServer(config);
        var client = new HttpClient(httpServer);

        //Act
        var response = await client.GetAsync("http://localhost/api/test/data");
        var returnJson = await response.Content.ReadAsStringAsync();

        //Assert
        response.IsSuccessStatusCode.Should().BeTrue();

        var result = JsonConvert.DeserializeObject<IEnumerable<Model>>(returnJson);
        result.First()
            .Should().NotBeNull()
            .And.Match<Model>(_ => _.Date == date);
    }
}

[RoutePrefix("api/test")]
public class TestApiController : ApiController {
    [HttpGet]
    [Route("data")]
    public IHttpActionResult Get() {
        var date = "22-Nov-18 12:00:00 AM";
        var dtoObject = new[] { new DTO { Date = date } };
        return Ok(dtoObject);
    }
}

Given that the assigned properties are strings, they should not be affected by date conversion.

The issue then would be how you are assigning the DateTime to the properties. Which could be as a result of the current culture the code is running under.

var value = new DTO { 
    Date = someDateTime.ToString()
};

which is where the desired date format should be applied

var value = new DTO { 
    Date = someDateTime.ToString("dd-MMM-yyyy hh:mm:ss tt")
};
Nkosi
  • 235,767
  • 35
  • 427
  • 472
0

Try using the ISO-8601 DateTime formater in WebAPI config for a consistent date format:

JsonSerializerSettings serializerSettings = new JsonSerializerSettings();
serializerSettings.Converters.Add(new IsoDateTimeConverter());
GlobalConfiguration.Configuration.Formatters[0] = new JsonNetFormatter(serializerSettings);

Dates will then be returned as:

{
   "Date": "2018-11-20T12:16:00"
}

In your client you need to expect the same format when deserializing the JSON to your internal object.

Rebecca
  • 13,914
  • 10
  • 95
  • 136
  • I can't find `JsonNetFormatter`. Do I need to add any reference for this class? BTW, Is it possible for the value to change while serializing/deserializing even when it is stored in a variable of type `string` ? – ravi kumar Nov 21 '18 at 06:45
  • I can't change the global settings. Is there any way to do it locally. – ravi kumar Nov 22 '18 at 09:38