2012-09-18 15 views
14

que tiene una función de JavaScript que llama a un controlador MVC con los datos JSON:forma correcta de convertir JSON Fecha de .NET DateTime Durante Deserialización

var specsAsJson = JSON.stringify(specs); 
$.post('/Home/Save', { jsonData: specsAsJson }); 

En el lado del servidor, dentro del controlador, parece que no puedo para conseguir más allá de este error:

/Date(1347992529530)/ is not a valid value for DateTime.

Esa excepción ocurre cuando llamo Deserialize() (tercera línea en el método a continuación):

public ActionResult Save(string jsonData) 
    { 
     var serializer = new JavaScriptSerializer(); 
     serializer.RegisterConverters(new[] { new TimeSpanJsonConverter() }); 
     var specs = serializer.Deserialize<List<EquipmentSpecWithParameterlessConstructor>>(jsonData); 

     return View("Index", _allTrackerJobs); 
    } 

He estado haciendo un poco de googlear, y el código anterior es mi último intento de hacer que esto funcione (usando TimeSpanJsonConverter de here). Otros enfoques muestran el envío de solo una fecha al servidor, pero tengo una lista de objetos que tienen fechas como algunas propiedades.

¿Existe un enfoque elegante y generalmente aceptado para resolver esto, o todavía necesitamos algún tipo de trabajo desagradable? ¿Cuál es la forma correcta de resolver esto?

Fin de =================== pregunta original ===================


Editar - resuelto por la serialización utilizando JsonConvert

Véase mi respuesta a continuación (no el trabajo en torno a mierda en esta pregunta).


Editar - malísima trabajo en torno

que creó un DTO con los mismos campos exactas como el objeto de dominio, excepto que hice las cadenas campos de fecha para que pudieran deserializar. Ahora que puedo deserializarlo, trabajaré para obtener las fechas en un formato válido para poder crear objetos de dominio desde mis DTO.

public class EquipmentSpecDto 
{ 
    public string StartTime { get; set; } 
    public string EndTime { get; set; } 
    // more properties here 
} 

Y yo simplemente utiliza el DTO para la deserialización:

var specs = serializer.Deserialize<List<EquipmentSpecDto>>(jsonData); 

Edición 2 - Conversión de JavaScript fechas a .NET

Para completar, y con la esperanza que salve a otra persona por hora, así es como pude convertir las fechas de javascript:

foreach (EquipmentSpecDto specDto in specDtos) 
    { 
     // JavaScript uses the unix epoch of 1/1/1970. Note, it's important to call ToLocalTime() 
     // after doing the time conversion, otherwise we'd have to deal with daylight savings hooey. 
     DateTime unixEpoch  = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc); 
     Double startMilliseconds = Convert.ToDouble(specDto.StartTime.Substring(6, 13)); 
     Double endMilliseconds = Convert.ToDouble(specDto.EndTime.Substring(6, 13)); 
     DateTime startTime  = unixEpoch.AddMilliseconds(startMilliseconds).ToLocalTime(); 
     DateTime endTime   = unixEpoch.AddMilliseconds(endMilliseconds).ToLocalTime(); 
     EquipmentSpec spec  = new EquipmentSpec(startTime, endTime, specDto.Equipment); 

     specs.Add(spec); 
    } 
+0

Parece que está pasando el objeto de fecha como datos de cadena, en lugar del valor real. Necesita convertir la fecha en milisegundos. –

+0

Cuando depuro.WriteLine() mi variable jsonData, parece que ya tiene milisegundos (truncado para facilitar la lectura): '[{" Id ": 1," TrackerJob ": null," Hora de inicio ":"/Fecha (1347993132851)/"," EndTime ":"/Date (1347993132851)/",' –

+0

Lo sentimos, no nos dimos cuenta de que C# tenía un formato específico para importar fechas. Esto puede ayudar: http://stackoverflow.com/questions/9374557/how-to-pass-timespan-value-in-json-format –

Respuesta

12

Encontré una respuesta simple. En mi javascript, estaba serializando los datos usando JavaScriptSerializer. Después de mucho googlear, encontré este article que muestra cómo serializar usando JsonConvert que hace que se use un DateTime .NET más amigable.

antigua:

var specs = @Html.Raw(new System.Web.Script.Serialization.JavaScriptSerializer().Serialize(ViewBag.JobSpecEquipment)) 

fechas aspecto: Date(1348017917565)

Nuevo:

var specs = @Html.Raw(Newtonsoft.Json.JsonConvert.SerializeObject(ViewBag.JobSpecEquipment)); 

fechas aspecto: 2012-09-18T21:27:31.1285861-04:00

Así que el problema fue realmente cómo estaba serializando en primer lugar. Una vez que usé JsonConvert, la deserialización en el back-end simplemente funcionó.

1

JavaScript (bueno, EcmaScript) define su formato de intercambio de cadenas DateTime basado en una simplificación del estándar ISO-8601.

XML Schema define su formato de intercambio de cadena DateTime basado también en ISO-8601.

He encontrado práctico utilizar la clase .NET System.Runtime.Remoting.Metadata.W3cXsd2001.SoapDateTime para manejar la conversión de .NET DateTime a formatos XML y viceversa.

Dado que JavaScript se basa en el mismo estándar ISO-8601, quizás también funcione para su caso JSON.

+0

Hmmm, tal vez podría usar esto para conectar los coverters de JavaScriptSerializer y convertir las fechas durante la deserialización. Voy a dar una oportunidad. –

+0

Intenté esto y terminé teniendo que administrar la serialización del gráfico de objetos y definitivamente no quiero involucrarme solo porque las fechas no coinciden. Por lo tanto, la conversión de las fechas parece bastante simple, pero no de una manera que ocurra automáticamente durante la deserialización. ¡Gracias por el consejo! –

3

Una cosa que atrapa a las personas con frecuencia al convertir entre fechas de Javascript y varios lenguajes del lado del servidor es que aunque ambas partes pueden entender un valor de marca de tiempo de estilo Unix, JS usa una marca de tiempo de microsegundos de precisión, mientras que en la mayoría otros idiomas, la precisión predeterminada de la marca de tiempo es la segunda.

En otras palabras, 1347993132851 en Javascript necesita ser dividido por 1000 para ser reconocido como una marca de tiempo Unix en otros idiomas.

Alternativamente, si su plataforma puede aceptar cadenas de fechas formateadas, use el objeto Javascript Date() para convertir un valor de marca de tiempo en una fecha formateada para enviar al servidor. O mejor aún, use una biblioteca auxiliar como Date.js o Moment.js.

+0

Esto es bueno saberlo.Con este enfoque, parece que tendría que encontrar todas las propiedades de datos en mi jerarquía de objetos y aplicar esta conversión de fecha. Sería bueno si pudiera deserializar en el servidor sin tener que buscar y actualizar todas las fechas. –

5

Encontré este código en Internet. funcionó como un encanto para mí ...

function customJSONstringify(obj) { 
    return JSON.stringify(obj).replace(/\/Date/g, "\\\/Date").replace(/\)\//g, "\)\\\/") 
} 
+0

Newtonsoft es la mejor manera de abordar el problema de la serialización JSON. Sin embargo, he votado a favor de esto porque es la respuesta correcta a la pregunta, cómo deserializar una fecha .NET. – styfle

+0

La mejor solución para mí, ya que trabajo en JavaScript y no puedo usar Newtonsoft. – Riga

1

Tomé respuesta @Bob Cuerno pero no funcionaba para mí. Mi servicio REST está usando fechas de Javascritpt. Adapte la respuesta referida a un método de extensión.


using System; 

namespace Mediatel.Framework 
{ 
    public static class JsonDate 
    { 
     public static DateTime ConvertToDateTime(this string jsonDate) 
     { 
      // JavaScript uses the unix epoch of 1/1/1970. Note, it's important to call ToLocalTime() 
      // after doing the time conversion, otherwise we'd have to deal with daylight savings hooey. 
      DateTime unixEpoch = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc); 
      Double milliseconds = Convert.ToDouble(jsonDate); 
      DateTime dateTime = unixEpoch.AddMilliseconds(milliseconds).ToLocalTime(); 

      return dateTime; 
     } 
    } 
} 
Cuestiones relacionadas